Skip to content

Commit 09e04a0

Browse files
committed
feat(consume): eofparse output is now correctly parsed into expected json format (ethereum#1232)
1 parent d08cdd7 commit 09e04a0

File tree

1 file changed

+112
-15
lines changed

1 file changed

+112
-15
lines changed

src/ethereum_clis/clis/geth.py

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -250,27 +250,71 @@ class GethFixtureConsumer(
250250
):
251251
"""Geth's implementation of the fixture consumer."""
252252

253-
def consume_blockchain_test(
253+
# ------------------------------------ eof test -----------------------------------------------
254+
255+
def extract_int_from_subprocess_string(
256+
self, s: str, substring_of_interest_prefix: str
257+
) -> int | None:
258+
"""Hacky method to extract relevant substring from string returned by subprocess execution.""" # noqa: E501
259+
# get everything after this substring occurrence, then remove everything not in [0,9]
260+
relevant_substring = re.sub(r"\D", "", s.split('total executed"=', 1)[1])
261+
if relevant_substring.isdigit():
262+
return int(relevant_substring)
263+
else:
264+
return None
265+
266+
def eofparse_subprocess_output_to_dict(
267+
self, process_result: str, fixture_name: str | None, fork_name: str
268+
) -> Dict:
269+
"""Take subprocess output from geth's eofparse, a fixture_name and a fork name and return relevant data as dict.""" # noqa: E501
270+
# remove whitespaces if more than 1 whitespace occurs at a time
271+
process_result_cleaned: str = re.sub(r"\s+", " ", process_result).strip()
272+
273+
# determine amount of total tests
274+
total_tests_amount: int | None = self.extract_int_from_subprocess_string(
275+
process_result_cleaned, 'total executed"='
276+
)
277+
278+
# determine amount of passed tests
279+
passed_tests_amount: int | None = self.extract_int_from_subprocess_string(
280+
process_result_cleaned, "tests passed="
281+
)
282+
283+
# determine if all tests of this test vector passed
284+
all_tests_passed: bool = False
285+
if total_tests_amount is not None and passed_tests_amount is not None:
286+
if total_tests_amount == passed_tests_amount:
287+
all_tests_passed = True
288+
289+
# return relevant data as dict
290+
return {
291+
"name": fixture_name,
292+
"pass": all_tests_passed,
293+
"stateRoot": None,
294+
"fork": fork_name,
295+
}
296+
297+
def consume_eof_test_file(
254298
self,
255299
fixture_path: Path,
256300
fixture_name: Optional[str] = None,
257301
debug_output_path: Optional[Path] = None,
258-
):
302+
) -> List[Dict[str, Any]]:
259303
"""
260-
Consume a single blockchain test.
304+
Consume an entire EOF validation test file.
261305
262-
The `evm blocktest` command takes the `--run` argument which can be used to select a
263-
specific fixture from the fixture file when executing.
306+
307+
The `evm eofparse` will always validate all the eof byte codes contained in a file without
308+
the possibility of selecting a single test, so this function is cached in order to only
309+
call the command once and `consume_eof_test` can simply select the result that was
310+
requested.
264311
"""
265-
subcommand = "blocktest"
312+
subcommand = "eofparse"
266313
global_options = []
267-
subcommand_options = []
314+
subcommand_options = ["--test"]
268315
if debug_output_path:
269316
global_options += ["--verbosity", "100"]
270-
subcommand_options += ["--trace"]
271-
272-
if fixture_name:
273-
subcommand_options += ["--run", re.escape(fixture_name)]
317+
# --trace does not exist for eofparse
274318

275319
command = (
276320
[str(self.binary)]
@@ -290,19 +334,69 @@ def consume_blockchain_test(
290334
f"Unexpected exit code:\n{' '.join(command)}\n\n Error:\n{result.stderr}"
291335
)
292336

337+
result_json = [
338+
self.eofparse_subprocess_output_to_dict(result.stderr, fixture_name, "Osaka")
339+
]
340+
if not isinstance(result_json, list):
341+
raise Exception(f"Unexpected result from evm eofparse: {result_json}")
342+
return result_json
343+
293344
def consume_eof_test(
294345
self,
295346
fixture_path: Path,
296347
fixture_name: Optional[str] = None,
297348
debug_output_path: Optional[Path] = None,
298349
):
299-
"""Consume an EOF validation test (valid yes/no) without running any EOF code."""
300-
subcommand = "eofparse"
350+
"""
351+
Consume a single eof test.
352+
353+
Uses the cached result from `consume_eof_test_file` in order to not call the command
354+
every time an select a single result from there.
355+
"""
356+
file_results = self.consume_eof_test_file(
357+
fixture_path=fixture_path,
358+
fixture_name=fixture_name,
359+
debug_output_path=debug_output_path,
360+
)
361+
if fixture_name:
362+
test_result = [
363+
test_result for test_result in file_results if test_result["name"] == fixture_name
364+
]
365+
assert len(test_result) < 2, f"Multiple test results for {fixture_name}"
366+
assert len(test_result) == 1, f"Test result for {fixture_name} missing"
367+
assert test_result[0]["pass"], f"EOF test failed: {test_result[0]['error']}"
368+
else:
369+
if any(not test_result["pass"] for test_result in file_results):
370+
exception_text = "EOF test failed: \n" + "\n".join(
371+
f"{test_result['name']}: " + test_result["error"]
372+
for test_result in file_results
373+
if not test_result["pass"]
374+
)
375+
raise Exception(exception_text)
376+
377+
# ---------------------------------- blockchain test ------------------------------------------
378+
379+
def consume_blockchain_test(
380+
self,
381+
fixture_path: Path,
382+
fixture_name: Optional[str] = None,
383+
debug_output_path: Optional[Path] = None,
384+
):
385+
"""
386+
Consume a single blockchain test.
387+
388+
The `evm blocktest` command takes the `--run` argument which can be used to select a
389+
specific fixture from the fixture file when executing.
390+
"""
391+
subcommand = "blocktest"
301392
global_options = []
302-
subcommand_options = ["--test"]
393+
subcommand_options = []
303394
if debug_output_path:
304395
global_options += ["--verbosity", "100"]
305-
# --trace does not exist for eofparse
396+
subcommand_options += ["--trace"]
397+
398+
if fixture_name:
399+
subcommand_options += ["--run", re.escape(fixture_name)]
306400

307401
command = (
308402
[str(self.binary)]
@@ -322,6 +416,8 @@ def consume_eof_test(
322416
f"Unexpected exit code:\n{' '.join(command)}\n\n Error:\n{result.stderr}"
323417
)
324418

419+
# ------------------------------------ state test ---------------------------------------------
420+
325421
@cache # noqa
326422
def consume_state_test_file(
327423
self,
@@ -361,6 +457,7 @@ def consume_state_test_file(
361457
)
362458

363459
result_json = json.loads(result.stdout)
460+
print("Output from json.loads(result.stdout):", result_json)
364461
if not isinstance(result_json, list):
365462
raise Exception(f"Unexpected result from evm statetest: {result_json}")
366463
return result_json

0 commit comments

Comments
 (0)