Skip to content

Commit dbb9928

Browse files
committed
Compare ethdebug output to program schema
1 parent f9a0985 commit dbb9928

File tree

5 files changed

+174
-0
lines changed

5 files changed

+174
-0
lines changed

.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:

test/ethdebugSchemaTests/conftest.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 = Path(tmpdir_factory.mktemp("data"))
26+
yield temporary_dir
27+
shutil.rmtree(temporary_dir)
28+
29+
30+
@pytest.fixture(scope="module")
31+
def ethdebug_schema_repository(ethdebug_clone_dir):
32+
process = subprocess.run(
33+
["git", "clone", "https://github.com/ethdebug/format.git", ethdebug_clone_dir],
34+
encoding='utf8',
35+
capture_output=True,
36+
check=True
37+
)
38+
assert process.returncode == 0
39+
40+
registry = referencing.Registry()
41+
for path in (ethdebug_clone_dir / "schemas").rglob("*.yaml"):
42+
with open(path, "r", encoding="utf8") as f:
43+
schema = yaml.safe_load(f)
44+
if "$id" in schema:
45+
resource = referencing.Resource.from_contents(schema, DRAFT202012)
46+
registry = resource @ registry
47+
else:
48+
raise ValueError(f"Schema did not define an $id: {path}")
49+
return registry
+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+
}
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,51 @@
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+
11+
def get_nested_value(dictionary, *keys):
12+
for key in keys:
13+
dictionary = dictionary[key]
14+
return dictionary
15+
16+
17+
@pytest.fixture(params=["input_file.json", "input_file_eof.json"])
18+
def solc_output(request, solc_path):
19+
testfile_dir = Path(__file__).parent
20+
with open(testfile_dir / request.param, "r", encoding="utf8") as f:
21+
source = json.load(f)
22+
23+
process = subprocess.run(
24+
[solc_path, "--standard-json"],
25+
input=json.dumps(source),
26+
encoding='utf8',
27+
capture_output=True,
28+
check=True,
29+
)
30+
assert process.returncode == 0
31+
return json.loads(process.stdout)
32+
33+
34+
@pytest.mark.parametrize("output_selection", ["evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"], ids=str)
35+
def test_program_schema(
36+
output_selection,
37+
ethdebug_schema_repository,
38+
solc_output
39+
):
40+
validator = jsonschema.Draft202012Validator(
41+
schema={"$ref": "schema:ethdebug/format/program"},
42+
registry=ethdebug_schema_repository
43+
)
44+
assert "contracts" in solc_output
45+
for contract in solc_output["contracts"].keys():
46+
contract_output = solc_output["contracts"][contract]
47+
assert len(contract_output) > 0
48+
for source in contract_output.keys():
49+
source_output = contract_output[source]
50+
ethdebug_data = get_nested_value(source_output, *(output_selection.split(".")))
51+
validator.validate(ethdebug_data)

0 commit comments

Comments
 (0)