Skip to content

Commit

Permalink
feat: initial support dencun (#677)
Browse files Browse the repository at this point in the history
* feat(wip): initial support dencun

* feat: add option to skip an entire directory

* feat: ignore BEACON_ROOT address in post_state

* feat: add fallback mechanism if secretKey is not found

* adapt blockchain-tests-skip.yml

* fix: fmt

* feat: support multi-tx blocks

* refactor: check case name end for fork name

* comment on multi-tx blocks'

* fix: add specific fork-filter case for Pyspec tests

* move secret_key fallback in secret_key()

* feat: base filter on formatted test identifier

* address review
  • Loading branch information
enitrat authored Mar 22, 2024
1 parent 5d0b86e commit 6ed1831
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 126 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ifneq ("$(wildcard .env)","")
endif

# The release tag of https://github.com/ethereum/tests to use for EF tests
EF_TESTS_TAG := v12.4
EF_TESTS_TAG := v13.2
EF_TESTS_URL := https://github.com/ethereum/tests/archive/refs/tags/$(EF_TESTS_TAG).tar.gz
EF_TESTS_DIR := ./crates/ef-testing/ethereum-tests

Expand Down
104 changes: 54 additions & 50 deletions blockchain-tests-skip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,66 @@
# The first level corresponds to the directory, the second to the list of file names regex to ignore.
# In the ef-tests repo, we skip all tests but the vmArithmeticTest.

directories:
- Pyspecs
- Cancun

filename:
None:
- None

testname:
vmArithmeticTest:
- addmod_d10g0v0_Shanghai
- addmod_d11g0v0_Shanghai
- addmod_d8g0v0_Shanghai
- addmod_d9g0v0_Shanghai
- divByZero_d63g0v0_Shanghai
- divByZero_d64g0v0_Shanghai
- divByZero_d65g0v0_Shanghai
- divByZero_d66g0v0_Shanghai
- divByZero_d67g0v0_Shanghai
- divByZero_d68g0v0_Shanghai
- divByZero_d69g0v0_Shanghai
- divByZero_d70g0v0_Shanghai
- divByZero_d71g0v0_Shanghai
- divByZero_d72g0v0_Shanghai
- divByZero_d73g0v0_Shanghai
- divByZero_d74g0v0_Shanghai
- divByZero_d75g0v0_Shanghai
- divByZero_d76g0v0_Shanghai
- divByZero_d77g0v0_Shanghai
- divByZero_d78g0v0_Shanghai
- divByZero_d79g0v0_Shanghai
- divByZero_d80g0v0_Shanghai
- divByZero_d81g0v0_Shanghai
- divByZero_d82g0v0_Shanghai
- divByZero_d83g0v0_Shanghai
- divByZero_d84g0v0_Shanghai
- divByZero_d85g0v0_Shanghai
- divByZero_d86g0v0_Shanghai
- divByZero_d87g0v0_Shanghai
- divByZero_d88g0v0_Shanghai
- divByZero_d89g0v0_Shanghai
- divByZero_d90g0v0_Shanghai
- divByZero_d91g0v0_Shanghai
- divByZero_d92g0v0_Shanghai
- divByZero_d93g0v0_Shanghai
- divByZero_d94g0v0_Shanghai
- divByZero_d95g0v0_Shanghai
- divByZero_d96g0v0_Shanghai
- divByZero_d97g0v0_Shanghai
- expPower256Of256_d0g0v0_Shanghai
- exp_d1g0v0_Shanghai
- exp_d3g0v0_Shanghai
- exp_d8g0v0_Shanghai
- exp_d9g0v0_Shanghai
- expPower256_d0g0v0_Shanghai
- mulmod_d12g0v0_Shanghai
- mulmod_d13g0v0_Shanghai
- mulmod_d14g0v0_Shanghai
- mulmod_d15g0v0_Shanghai
- twoOps_d0g0v0_Shanghai
- addmod_d10g0v0_Cancun
- addmod_d11g0v0_Cancun
- addmod_d8g0v0_Cancun
- addmod_d9g0v0_Cancun
- divByZero_d63g0v0_Cancun
- divByZero_d64g0v0_Cancun
- divByZero_d65g0v0_Cancun
- divByZero_d66g0v0_Cancun
- divByZero_d67g0v0_Cancun
- divByZero_d68g0v0_Cancun
- divByZero_d69g0v0_Cancun
- divByZero_d70g0v0_Cancun
- divByZero_d71g0v0_Cancun
- divByZero_d72g0v0_Cancun
- divByZero_d73g0v0_Cancun
- divByZero_d74g0v0_Cancun
- divByZero_d75g0v0_Cancun
- divByZero_d76g0v0_Cancun
- divByZero_d77g0v0_Cancun
- divByZero_d78g0v0_Cancun
- divByZero_d79g0v0_Cancun
- divByZero_d80g0v0_Cancun
- divByZero_d81g0v0_Cancun
- divByZero_d82g0v0_Cancun
- divByZero_d83g0v0_Cancun
- divByZero_d84g0v0_Cancun
- divByZero_d85g0v0_Cancun
- divByZero_d86g0v0_Cancun
- divByZero_d87g0v0_Cancun
- divByZero_d88g0v0_Cancun
- divByZero_d89g0v0_Cancun
- divByZero_d90g0v0_Cancun
- divByZero_d91g0v0_Cancun
- divByZero_d92g0v0_Cancun
- divByZero_d93g0v0_Cancun
- divByZero_d94g0v0_Cancun
- divByZero_d95g0v0_Cancun
- divByZero_d96g0v0_Cancun
- divByZero_d97g0v0_Cancun
- expPower256Of256_d0g0v0_Cancun
- exp_d1g0v0_Cancun
- exp_d3g0v0_Cancun
- exp_d8g0v0_Cancun
- exp_d9g0v0_Cancun
- expPower256_d0g0v0_Cancun
- mulmod_d12g0v0_Cancun
- mulmod_d13g0v0_Cancun
- mulmod_d14g0v0_Cancun
- mulmod_d15g0v0_Cancun
- twoOps_d0g0v0_Cancun

regex:
stArgsZeroOneBalance:
Expand Down
1 change: 1 addition & 0 deletions crates/build-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
walkdir = { workspace = true }
reth-primitives = { workspace = true }
33 changes: 32 additions & 1 deletion crates/build-utils/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,33 @@
use lazy_static::lazy_static;
use reth_primitives::alloy_primitives::{address, Address};
use std::collections::HashMap;

pub const ROOT: &str = "GeneralStateTests";
pub const FORK: &str = "Shanghai";
pub const FORK: &str = "Cancun";

lazy_static! {
// A registry of the most common addresses and their associated secret keys.
// Most secret keys can be read from filler files directly - however, for python-based
// tests, the secret keys are not present in the filler files. This registry
// is used to fill in the missing secret keys (only two used in pyspec tests).
pub static ref ADDRESSES_KEYS: HashMap<Address, &'static str> = {
let mut registry = HashMap::new();
registry.insert(
address!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
"0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
);
registry.insert(
address!("8a0a19589531694250d570040a0c4b74576919b8"),
"0x9e7645d0cfd9c3a04eb7a9db59a4eb7d359f2e75c9164a9d6b9a7d54e1b6a36f",
);
registry.insert(
address!("d02d72e067e77158444ef2020ff2d325f929b363"),
"41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298",
);
registry.insert(
address!("97a7cb1de3cc7d556d0aa32433b035067709e1fc"),
"0x0b2986cc45bd8a8d028c3fcf6f7a11a52f1df61f3ea5d63f05ca109dd73a3fa0"
);
registry
};
}
74 changes: 65 additions & 9 deletions crates/build-utils/src/content_reader.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::collections::BTreeMap;

use reth_primitives::{revm_primitives::FixedBytes, Address};
use serde_json::Value;

use crate::{path::PathWrapper, utils::blockchain_tests_to_general_state_tests_path};
use crate::{
constants::ADDRESSES_KEYS, path::PathWrapper,
utils::blockchain_tests_to_general_state_tests_path,
};

/// The `ContentReader` is used to read the content of the ef-test tests files.
/// The tests files are located in the `BlockchainTests` folder and contain
Expand All @@ -22,20 +26,45 @@ impl ContentReader {
///
/// Test location: BlockchainTests/GeneralStateTests/stRandom/randomStatetest0.json
/// Secret key location: GeneralStateTests/stRandom/randomStatetest0.json
pub fn secret_key(path: PathWrapper) -> Result<Option<Value>, eyre::Error> {
pub fn secret_key(
path: PathWrapper,
case_without_secret: &Value,
) -> Result<String, eyre::Error> {
let path = blockchain_tests_to_general_state_tests_path(path);
let content = path.read_file_to_string()?;
let maybe_content_with_secret = path.read_file_to_string();
let case = match maybe_content_with_secret {
Ok(content) => {
let cases: BTreeMap<String, Value> = serde_json::from_str(&content)?;
cases.into_values().next()
}
Err(_) => Some(case_without_secret.clone()),
};

let cases: BTreeMap<String, Value> = serde_json::from_str(&content)?;
let case = cases.into_values().next();

Ok(case
let key = match case
.as_ref()
.and_then(|value| value.get("transaction"))
.and_then(|value| value.get("secretKey"))
.cloned())
}
{
Some(key) => key.to_string(),
None => {
let block = Self::block(case_without_secret)?;
let transaction = Self::transaction(case_without_secret, &block)?;
let sender = transaction
.get("sender")
.and_then(|value| value.as_str())
.ok_or_else(|| eyre::eyre!("Key 'sender' not found"))?;

let sender_address: Address = sender.parse::<FixedBytes<20>>()?.into();
ADDRESSES_KEYS
.get(&sender_address)
.map(|addr| format!("\"{}\"", addr))
.unwrap_or_else(|| panic!("No secret key found for {sender_address}"))
}
};
Ok(key)
}
// Ok(
// ))
pub fn pre_state(test_case: &Value) -> Result<Value, eyre::Error> {
Ok(serde_json::from_value(
test_case
Expand Down Expand Up @@ -71,4 +100,31 @@ impl ContentReader {
// Return a clone of the block
Ok(first_block.clone())
}

pub fn transaction(test_case: &Value, block: &Value) -> Result<Value, eyre::Error> {
let maybe_transaction = block.get("transactions");

match maybe_transaction {
Some(transaction) => {
// Ensure it's an array
let transaction_array = transaction
.as_array()
.ok_or_else(|| eyre::eyre!("'transactions' is not an array"))?;

// Get the first transaction - multi-txs tests are not supported by the runner
let first_tx = transaction_array
.first()
.ok_or_else(|| eyre::eyre!("'transactions' array is empty"))?;

Ok(first_tx.clone())
}
None => {
let transaction = test_case
.get("transaction")
.ok_or_else(|| eyre::eyre!("key 'transaction' not found"))?;

Ok(transaction.clone())
}
}
}
}
62 changes: 47 additions & 15 deletions crates/build-utils/src/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ use crate::{
///
/// Test location: BlockchainTests/GeneralStateTests/stRandom/
/// List of tests: [randomStatetest0.json, randomStatetest1.json, ...]
/// Inner tests: [`randomStatetest0_d0g0v0_Shanghai`, `randomStatetest0_d1g0v0_Shanghai`,
/// ..., `randomStatetest1_d0g0v0_Shanghai`, `randomStatetest1_d1g0v0_Shanghai`, ...]
/// Inner tests: [`randomStatetest0_d0g0v0_Cancun`, `randomStatetest0_d1g0v0_Cancun`,
/// ..., `randomStatetest1_d0g0v0_Cancun`, `randomStatetest1_d1g0v0_Cancun`, ...]
/// Generated String:
/// r#"
/// mod randomStatetest0 {
/// use super::*;
/// #[test]
/// fn test_randomStatetest0_d0g0v0_Shanghai() {
/// fn test_randomStatetest0_d0g0v0_Cancun() {
/// ...
/// }
/// #[test]
/// fn test_randomStatetest0_d1g0v0_Shanghai() {
/// fn test_randomStatetest0_d1g0v0_Cancun() {
/// ...
/// }
/// #[test]
/// fn test_randomStatetest1_d0g0v0_Shanghai() {
/// fn test_randomStatetest1_d0g0v0_Cancun() {
/// ...
/// }
/// #[test]
/// fn test_randomStatetest1_d1g0v0_Shanghai() {
/// fn test_randomStatetest1_d1g0v0_Cancun() {
/// ...
/// }
/// ...
Expand Down Expand Up @@ -93,12 +93,16 @@ impl<'a> EfTests<'a> {
let file_contents = cases
.par_iter()
.map(|(case_name, content)| {
if !case_name.contains(FORK) {
if !(case_name.ends_with(FORK) || case_name.contains(&format!("fork_{}", FORK)))
{
return Ok(String::new());
}
let secret_key = ContentReader::secret_key(file_path.clone())?
.ok_or_else(|| eyre::eyre!("Missing secret key"))?;
let is_skipped = self.filter.is_skipped(file_path, Some(case_name.clone()));
let secret_key = if is_skipped {
String::default() // secret key is not needed if the test is skipped
} else {
ContentReader::secret_key(file_path.clone(), content)?
};
Self::format_to_test(case_name, parent_dir, &secret_key, content, is_skipped)
})
.collect::<Result<Vec<String>, eyre::Error>>()?;
Expand Down Expand Up @@ -140,7 +144,7 @@ impl<'a> EfTests<'a> {
fn format_to_test(
case_name: &str,
parent_dir: &str,
secret_key: &Value,
secret_key: &String,
content: &Value,
is_skipped: bool,
) -> Result<String, eyre::Error> {
Expand All @@ -166,7 +170,7 @@ impl<'a> EfTests<'a> {
fn format_test_content(
case_name: &str,
parent_dir: &str,
secret_key: &Value,
secret_key: &String,
content: &Value,
is_skipped: bool,
) -> Result<String, eyre::Error> {
Expand Down Expand Up @@ -198,9 +202,37 @@ impl<'a> EfTests<'a> {
}

/// Formats the given string into a valid rust identifier.
fn format_into_identifier(s: &str) -> String {
s.replace('-', "_minus_")
.replace('+', "_plus_")
.replace('^', "_xor_")
pub fn format_into_identifier(s: &str) -> String {
// Pyspec tests are in form test_src/GeneralStateTestsFillerFiller/Pyspecs/berlin/eip2930_access_list/test_acl.py::test_access_list[fork_Cancun_minus_blockchain_test]()
// We only keep the test name and its parameters.
if s.contains("Pyspecs") {
let test_name = s
.split('/')
.last()
.unwrap_or_default()
.split("::")
.last()
.unwrap_or_default();

let test_name = test_name
.to_string()
.replace("test_", "")
.replace('(', "_lpar_")
.replace(')', "_rpar")
.replace('[', "__")
.replace(']', "")
.replace('-', "_minus_")
.split(',')
.map(|part| part.trim())
.collect::<Vec<_>>()
.join("_");

// add the fork name after the test name
test_name
} else {
s.replace('-', "_minus_")
.replace('+', "_plus_")
.replace('^', "_xor_")
}
}
}
Loading

0 comments on commit 6ed1831

Please sign in to comment.