Skip to content

Commit dbdbc38

Browse files
committed
Compare ethdebug output to program schema
1 parent db53ca5 commit dbdbc38

File tree

5 files changed

+171
-0
lines changed

5 files changed

+171
-0
lines changed

Diff for: .circleci/config.yml

+18
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,8 @@ jobs:
951951
chk_pylint:
952952
<<: *base_ubuntu2404_small
953953
steps:
954+
- install_python3:
955+
packages: pyyaml jsonschema pytest
954956
- checkout
955957
- run: pylint --version
956958
- run:
@@ -1534,6 +1536,19 @@ jobs:
15341536
- reports/externalTests/
15351537
- matrix_notify_failure_unless_pr
15361538

1539+
t_ethdebug_output_validity:
1540+
<<: *base_node_small
1541+
steps:
1542+
- checkout
1543+
- attach_workspace:
1544+
at: /tmp/workspace
1545+
- install_python3:
1546+
packages: pyyaml jsonschema pytest
1547+
- run:
1548+
name: Ethdebug validity tests
1549+
command: |
1550+
pytest test/ethdebugSchemaTests --solc-binary-path=/tmp/workspace/solc/solc-static-linux -v
1551+
15371552
c_ext_benchmarks:
15381553
<<: *base_node_small
15391554
steps:
@@ -1927,6 +1942,9 @@ workflows:
19271942
#- t_ext: *job_native_compile_ext_chainlink
19281943
#- t_ext: *job_native_compile_ext_bleeps
19291944

1945+
- t_ethdebug_output_validity:
1946+
<<: *requires_b_ubu_static
1947+
19301948
- c_ext_benchmarks:
19311949
<<: *requires_nothing
19321950
requires:

Diff for: test/ethdebugSchemaTests/conftest.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import shutil
2+
import subprocess
3+
from pathlib import Path
4+
5+
import pytest
6+
import referencing
7+
import yaml
8+
from referencing.jsonschema import DRAFT202012
9+
10+
11+
def pytest_addoption(parser):
12+
parser.addoption("--solc-binary-path", type=Path, required=True, help="Path to the solidity compiler binary.")
13+
14+
15+
@pytest.fixture
16+
def solc_path(request):
17+
solc_path = request.config.getoption("--solc-binary-path")
18+
assert solc_path.is_file()
19+
assert solc_path.exists()
20+
return solc_path
21+
22+
23+
@pytest.fixture(scope="module")
24+
def ethdebug_clone_dir(tmpdir_factory):
25+
temporary_dir = tmpdir_factory.mktemp("data")
26+
yield Path(temporary_dir)
27+
shutil.rmtree(str(temporary_dir))
28+
29+
@pytest.fixture(scope="module")
30+
def ethdebug_schema_repository(ethdebug_clone_dir):
31+
process = subprocess.run(
32+
["git", "clone", "https://github.com/ethdebug/format.git", ethdebug_clone_dir],
33+
encoding='utf8',
34+
capture_output=True,
35+
check=True
36+
)
37+
assert process.returncode == 0
38+
39+
registry = referencing.Registry()
40+
for path in (ethdebug_clone_dir / "schemas").rglob("*.yaml"):
41+
with open(path, "r", encoding="utf8") as f:
42+
schema = yaml.safe_load(f)
43+
if "$id" in schema:
44+
resource = referencing.Resource.from_contents(schema, DRAFT202012)
45+
registry = resource @ registry
46+
else:
47+
raise ValueError(f"Schema did not define an $id: {path}")
48+
return registry

Diff for: test/ethdebugSchemaTests/input_file.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"language": "Solidity",
3+
"sources": {
4+
"a.sol": {
5+
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }"
6+
},
7+
"b.sol": {
8+
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }"
9+
}
10+
},
11+
"settings": {
12+
"viaIR": true,
13+
"debug": {
14+
"debugInfo": [
15+
"ethdebug"
16+
]
17+
},
18+
"outputSelection": {
19+
"*": {
20+
"*": [
21+
"evm.bytecode.ethdebug",
22+
"evm.deployedBytecode.ethdebug"
23+
]
24+
}
25+
}
26+
}
27+
}

Diff for: test/ethdebugSchemaTests/input_file_eof.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"language": "Solidity",
3+
"sources": {
4+
"a.sol": {
5+
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }"
6+
},
7+
"b.sol": {
8+
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }"
9+
}
10+
},
11+
"settings": {
12+
"eofVersion": 1,
13+
"evmVersion": "osaka",
14+
"viaIR": true,
15+
"debug": {
16+
"debugInfo": [
17+
"ethdebug"
18+
]
19+
},
20+
"outputSelection": {
21+
"*": {
22+
"*": [
23+
"evm.bytecode.ethdebug",
24+
"evm.deployedBytecode.ethdebug"
25+
]
26+
}
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
3+
import json
4+
import subprocess
5+
from pathlib import Path
6+
7+
import jsonschema
8+
import pytest
9+
10+
def get_nested_value(dictionary, *keys):
11+
for key in keys:
12+
dictionary = dictionary[key]
13+
return dictionary
14+
15+
@pytest.fixture(params=["input_file.json", "input_file_eof.json"])
16+
def solc_output(request, solc_path):
17+
testfile_dir = Path(__file__).parent
18+
with open(testfile_dir / request.param, "r", encoding="utf8") as f:
19+
source = json.load(f)
20+
21+
process = subprocess.run(
22+
[solc_path, "--standard-json"],
23+
input=json.dumps(source),
24+
encoding='utf8',
25+
capture_output=True,
26+
check=True,
27+
)
28+
assert process.returncode == 0
29+
return json.loads(process.stdout)
30+
31+
32+
@pytest.mark.parametrize("output_selection", ["evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"], ids=str)
33+
def test_ethdebug_program_schema_conformity(
34+
output_selection,
35+
ethdebug_schema_repository,
36+
solc_output
37+
):
38+
validator = jsonschema.Draft202012Validator(
39+
schema={"$ref": "schema:ethdebug/format/program"},
40+
registry=ethdebug_schema_repository
41+
)
42+
assert "contracts" in solc_output
43+
for contract in solc_output["contracts"].keys():
44+
contract_output = solc_output["contracts"][contract]
45+
assert len(contract_output) > 0
46+
for source in contract_output.keys():
47+
source_output = contract_output[source]
48+
ethdebug_data = get_nested_value(source_output, *(output_selection.split(".")))
49+
validator.validate(ethdebug_data)

0 commit comments

Comments
 (0)