Skip to content

Commit 2d049b9

Browse files
authored
feat(levm): improve state EF Tests (#2490)
**Motivation** - Make running and modifying EF Tests a better experience **Description** <!-- A clear and concise general description of the changes this PR introduces --> - Remove spinner and just use prints - We now can filter the tests we want to run by fork name(we do the filtering in the parsing). Default is all forks. - Upgrade tests to more recent version - Run some Legacy Tests that we weren't running before. This adds a lot of tests more, it is the folder Cancun under LegacyTests. There will be repeated tests with the folder GeneralStateTests, we may want to find a solution for that so that it takes less time to execute. - Create docs in `README.md` - Implement some nits in the runner, making code easier to understand. - Ignore a few tests that take too long to run so that we can check for breaking changes fast. - Fix comparison report against LEVM, they weren't working correctly mostly because we were mishandling our Cache - Tidy the report, now it is much more clear and easier for debugging. Also the code is easier to follow and more concise too! - Fix some tests with REVM, basically now using constructor of `BlobExcessGasAndPrice` and setting chain id to 1 (as we do in LEVM). - Changed `get_state_transitions` [here](#2518) so that REVM and LEVM account updates are mostly the same and the comparison is more accurate for the person who is debugging any test. <!-- Link to issues: Resolves #111, Resolves #222 --> Closes #issue_number
1 parent 4e6a960 commit 2d049b9

File tree

11 files changed

+355
-547
lines changed

11 files changed

+355
-547
lines changed

cmd/ef_tests/state/README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
11
# State Tests
22

3-
https://ethereum.github.io/execution-spec-tests/main/consuming_tests/state_test/
3+
The state tests are individual transactions not related one to each other that test particular behavior of the EVM. Tests are usually run for multiple forks and the result of execution may vary between forks.
4+
Some [docs](https://ethereum.github.io/execution-spec-tests/main/consuming_tests/state_test/).
5+
46

57
## Running the tests
68

79
```bash
8-
make run-evm-ef-tests
10+
make run-evm-ef-tests flags=<flags>
11+
```
12+
or
13+
```bash
14+
cargo test --package ef_tests-state --test all --release -- <flags>
915
```
16+
17+
**Flags**
18+
- forks: Forks for which we want to run the tests for.
19+
- tests: Tests (.json files) we want to run
20+
- specific_tests: For running tests with a specific name. (Sometimes a .json file has multiple tests)
21+
- summary: For not doing a re-run with REVM of failed tests after LEVM's run.
22+
- skip: For skipping tests
23+
- verbose: For more info while running, like tests names being run.
24+
- revm: For running EFTests ONLY with REVM.
25+
26+
27+
Example usage:
28+
```bash
29+
cargo test --package ef_tests-state --test all --release -- --forks Prague,Cancun --summary --tests push0.json,invalidAddr.json
30+
```
31+
This runs 2 specific tests with LEVM just for Prague and Cancun. If they fail they are not re-run with REVM.
32+
33+
Most of the tests that we run are from [this repository](https://github.com/ethereum/tests). We run the `GeneralStateTests` from that repo and also from `LegacyTests`, which is another repository that has snapshots of tests from previous forks.
34+
35+
36+
Beware: Sometimes there is a test overlap between the tests folders we have downloaded and we may run the same test for a recent fork (Cancun ATTOW) twice. The impact of this in performance is minimal because we are doing runs for other forks anyway so one more run won't harm, but we should be aware that may lead to an inaccurate test count. We chose not to handle this because it wasn't a huge problem, but be conscious about this.

cmd/ef_tests/state/deserialize.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ where
6868
"TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS" => {
6969
TransactionExpectedException::InsufficientMaxFeePerBlobGas
7070
}
71-
other => panic!("Unexpected error type: {}", other), // Should not fail, TODO is to return an error
71+
_other => TransactionExpectedException::Other, //TODO: Support exceptions that enter here.
7272
})
7373
.collect();
7474

cmd/ef_tests/state/parser.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ use crate::{
22
report::format_duration_as_mm_ss,
33
runner::EFTestRunnerOptions,
44
types::{EFTest, EFTests},
5-
utils::{spinner_success_or_print, spinner_update_text_or_print},
65
};
76
use colored::Colorize;
8-
use spinoff::{spinners::Dots, Color, Spinner};
97
use std::fs::DirEntry;
108

119
#[derive(Debug, thiserror::Error)]
@@ -20,9 +18,12 @@ pub enum EFTestParseError {
2018
FailedToParseTestFile(String),
2119
}
2220

23-
const IGNORED_TESTS: [&str; 8] = [
24-
"ValueOverflowParis.json", // Skip because of errors
25-
"loopMul.json", // Skip because it takes too long to run
21+
const IGNORED_TESTS: [&str; 11] = [
22+
"static_Call50000_sha256.json", // Skip because it takes longer to run than some tests, but not a huge deal.
23+
"CALLBlake2f_MaxRounds.json", // Skip because it takes extremely long to run, but passes.
24+
"ValueOverflow.json", // Skip because it tries to deserialize number > U256::MAX
25+
"ValueOverflowParis.json", // Skip because it tries to deserialize number > U256::MAX
26+
"loopMul.json", // Skip because it takes too long to run
2627
"dynamicAccountOverwriteEmpty_Paris.json", // Skip because it fails on REVM
2728
"RevertInCreateInInitCreate2Paris.json", // Skip because it fails on REVM. See https://github.com/lambdaclass/ethrex/issues/1555
2829
"RevertInCreateInInit_Paris.json", // Skip because it fails on REVM. See https://github.com/lambdaclass/ethrex/issues/1555
@@ -35,10 +36,8 @@ pub fn parse_ef_tests(opts: &EFTestRunnerOptions) -> Result<Vec<EFTest>, EFTestP
3536
let parsing_time = std::time::Instant::now();
3637
let cargo_manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
3738
let ef_general_state_tests_path = cargo_manifest_dir.join("vectors");
38-
let mut spinner = Spinner::new(Dots, "Parsing EF Tests".bold().to_string(), Color::Cyan);
39-
if !opts.spinner {
40-
spinner.stop();
41-
}
39+
println!("{}", "Parsing EF Tests".bold().cyan());
40+
4241
let mut tests = Vec::new();
4342
for test_dir in std::fs::read_dir(ef_general_state_tests_path.clone())
4443
.map_err(|err| {
@@ -49,17 +48,13 @@ pub fn parse_ef_tests(opts: &EFTestRunnerOptions) -> Result<Vec<EFTest>, EFTestP
4948
})?
5049
.flatten()
5150
{
52-
let directory_tests = parse_ef_test_dir(test_dir, opts, &mut spinner)?;
51+
let directory_tests = parse_ef_test_dir(test_dir, opts)?;
5352
tests.extend(directory_tests);
5453
}
5554

56-
spinner_success_or_print(
57-
&mut spinner,
58-
format!(
59-
"Parsed EF Tests in {}",
60-
format_duration_as_mm_ss(parsing_time.elapsed())
61-
),
62-
opts.spinner,
55+
println!(
56+
"Parsed EF Tests in {}",
57+
format_duration_as_mm_ss(parsing_time.elapsed())
6358
);
6459

6560
Ok(tests)
@@ -68,13 +63,8 @@ pub fn parse_ef_tests(opts: &EFTestRunnerOptions) -> Result<Vec<EFTest>, EFTestP
6863
pub fn parse_ef_test_dir(
6964
test_dir: DirEntry,
7065
opts: &EFTestRunnerOptions,
71-
directory_parsing_spinner: &mut Spinner,
7266
) -> Result<Vec<EFTest>, EFTestParseError> {
73-
spinner_update_text_or_print(
74-
directory_parsing_spinner,
75-
format!("Parsing directory {:?}", test_dir.file_name()),
76-
opts.spinner,
77-
);
67+
println!("Parsing directory {:?}", test_dir.file_name());
7868

7969
let mut directory_tests = Vec::new();
8070
for test in std::fs::read_dir(test_dir.path())
@@ -90,7 +80,7 @@ pub fn parse_ef_test_dir(
9080
})?
9181
.is_dir()
9282
{
93-
let sub_directory_tests = parse_ef_test_dir(test, opts, directory_parsing_spinner)?;
83+
let sub_directory_tests = parse_ef_test_dir(test, opts)?;
9484
directory_tests.extend(sub_directory_tests);
9585
continue;
9686
}
@@ -132,13 +122,9 @@ pub fn parse_ef_test_dir(
132122
.skip
133123
.contains(&test_dir.file_name().to_str().unwrap().to_owned())
134124
{
135-
spinner_update_text_or_print(
136-
directory_parsing_spinner,
137-
format!(
138-
"Skipping test {:?} as it is in the folder of tests to skip",
139-
test.path().file_name().unwrap()
140-
),
141-
opts.spinner,
125+
println!(
126+
"Skipping test {:?} as it is in the folder of tests to skip",
127+
test.path().file_name().unwrap()
142128
);
143129
continue;
144130
}
@@ -153,13 +139,9 @@ pub fn parse_ef_test_dir(
153139
.unwrap()
154140
.to_owned(),
155141
) {
156-
spinner_update_text_or_print(
157-
directory_parsing_spinner,
158-
format!(
159-
"Skipping test {:?} as it is in the list of tests to skip",
160-
test.path().file_name().unwrap()
161-
),
162-
opts.spinner,
142+
println!(
143+
"Skipping test file {:?} as it is in the list of tests to skip",
144+
test.path().file_name().unwrap()
163145
);
164146
continue;
165147
}
@@ -173,6 +155,24 @@ pub fn parse_ef_test_dir(
173155
for test in tests.0.iter_mut() {
174156
test.dir = test_dir.file_name().into_string().unwrap();
175157
}
158+
159+
// We only want to include tests that have post states from the specified forks in EFTestsRunnerOptions.
160+
if let Some(forks) = &opts.forks {
161+
for test in tests.0.iter_mut() {
162+
let test_forks_numbers: Vec<u8> = forks.iter().map(|fork| *fork as u8).collect();
163+
164+
test.post.forks = test
165+
.post
166+
.forks
167+
.iter()
168+
.filter(|a| test_forks_numbers.contains(&(*a.0 as u8)))
169+
.map(|(k, v)| (*k, v.clone()))
170+
.collect();
171+
}
172+
173+
tests.0.retain(|test| !test.post.forks.is_empty());
174+
}
175+
176176
directory_tests.extend(tests.0);
177177
}
178178
Ok(directory_tests)

0 commit comments

Comments
 (0)