Skip to content

Commit 76d6a0f

Browse files
feat[tool]: add venom artifacts into solc_json output (#4637)
this commit adds venom output keys `bb/bb_runtime` and `cfg/cfg_runtime` into the output artifact when calling `compile_json()`, adding extra information for downstream tooling to display. --------- Co-authored-by: Charles Cooper <cooper.charles.m@gmail.com>
1 parent d8a143d commit 76d6a0f

File tree

3 files changed

+109
-21
lines changed

3 files changed

+109
-21
lines changed

tests/unit/cli/vyper_json/test_compile_json.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import vyper
77
from vyper.cli.vyper_json import (
8+
VENOM_KEYS,
89
compile_from_input_dict,
910
compile_json,
1011
exc_handler_to_dict,
@@ -145,15 +146,11 @@ def json_input(json_data, path):
145146
)
146147

147148

148-
def test_compile_json(input_json, input_bundle):
149+
def test_compile_json(input_json, input_bundle, experimental_codegen):
149150
foo_input = input_bundle.load_file("contracts/foo.vy")
150151
# remove venom related from output formats
151152
# because they require venom (experimental)
152153
output_formats = OUTPUT_FORMATS.copy()
153-
del output_formats["bb"]
154-
del output_formats["bb_runtime"]
155-
del output_formats["cfg"]
156-
del output_formats["cfg_runtime"]
157154
foo = compile_from_file_input(
158155
foo_input,
159156
output_formats=output_formats,
@@ -198,7 +195,7 @@ def test_compile_json(input_json, input_bundle):
198195
"ast": data["ast_dict"]["ast"],
199196
"annotated_ast": data["annotated_ast_dict"]["ast"],
200197
}
201-
assert output_json["contracts"][path][contract_name] == {
198+
expected = {
202199
"abi": data["abi"],
203200
"devdoc": data["devdoc"],
204201
"interface": data["interface"],
@@ -220,6 +217,14 @@ def test_compile_json(input_json, input_bundle):
220217
"methodIdentifiers": data["method_identifiers"],
221218
},
222219
}
220+
if experimental_codegen:
221+
expected["venom"] = {
222+
"bb": repr(data["bb"]),
223+
"bb_runtime": repr(data["bb_runtime"]),
224+
"cfg": data["cfg"],
225+
"cfg_runtime": data["cfg_runtime"],
226+
}
227+
assert output_json["contracts"][path][contract_name] == expected
223228

224229

225230
def test_compilation_targets(input_json):
@@ -237,7 +242,7 @@ def test_compilation_targets(input_json):
237242
assert list(output_json["contracts"].keys()) == ["contracts/foo.vy", "contracts/bar.vy"]
238243

239244

240-
def test_different_outputs(input_bundle, input_json):
245+
def test_different_outputs(input_bundle, input_json, experimental_codegen):
241246
input_json["settings"]["outputSelection"] = {
242247
"contracts/bar.vy": "*",
243248
"contracts/foo.vy": ["evm.methodIdentifiers"],
@@ -252,16 +257,11 @@ def test_different_outputs(input_bundle, input_json):
252257

253258
foo = contracts["contracts/foo.vy"]["foo"]
254259
bar = contracts["contracts/bar.vy"]["bar"]
255-
assert sorted(bar.keys()) == [
256-
"abi",
257-
"devdoc",
258-
"evm",
259-
"interface",
260-
"ir",
261-
"layout",
262-
"metadata",
263-
"userdoc",
264-
]
260+
expected_keys = ["abi", "devdoc", "evm", "interface", "ir", "layout", "metadata", "userdoc"]
261+
if experimental_codegen:
262+
expected_keys.append("venom")
263+
expected_keys.sort()
264+
assert sorted(bar.keys()) == expected_keys
265265

266266
assert sorted(foo.keys()) == ["evm"]
267267

@@ -385,13 +385,41 @@ def test_compile_json_with_experimental_codegen():
385385
"evmVersion": "cancun",
386386
"optimize": "gas",
387387
"venomExperimental": True,
388-
"search_paths": [],
389-
"outputSelection": {"*": ["ast"]},
388+
"search_paths": ["."],
389+
"outputSelection": {"*": VENOM_KEYS},
390390
},
391391
}
392+
compiled = compile_from_input_dict(code)
393+
expected = compiled[0][PurePath("foo.vy")]
392394

393395
settings = get_settings(code)
394396
assert settings.experimental_codegen is True
397+
output_json = compile_json(code)
398+
assert "venom" in output_json["contracts"]["foo.vy"]["foo"]
399+
venom = output_json["contracts"]["foo.vy"]["foo"]["venom"]
400+
assert venom["bb"] == repr(expected["bb"])
401+
assert venom["bb_runtime"] == repr(expected["bb_runtime"])
402+
assert venom["cfg"] == expected["cfg"]
403+
assert venom["cfg_runtime"] == expected["cfg_runtime"]
404+
405+
406+
def test_compile_json_without_experimental_codegen():
407+
code = {
408+
"language": "Vyper",
409+
"sources": {"foo.vy": {"content": "@external\ndef foo() -> bool:\n return True"}},
410+
"settings": {
411+
"evmVersion": "cancun",
412+
"optimize": "gas",
413+
"venomExperimental": False,
414+
"search_paths": ["."],
415+
"outputSelection": {"*": ["ast"]},
416+
},
417+
}
418+
419+
settings = get_settings(code)
420+
assert settings.experimental_codegen is False
421+
output_json = compile_json(code)
422+
assert "venom" not in output_json["contracts"]["foo.vy"]["foo"]
395423

396424

397425
def test_compile_json_with_both_venom_aliases():

tests/unit/cli/vyper_json/test_output_selection.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from vyper import compiler
6-
from vyper.cli.vyper_json import TRANSLATE_MAP, get_output_formats
6+
from vyper.cli.vyper_json import TRANSLATE_MAP, VENOM_KEYS, get_output_formats
77
from vyper.exceptions import JSONError
88

99

@@ -33,6 +33,19 @@ def test_translate_map(output):
3333
"sources": {"foo.vy": ""},
3434
"settings": {"outputSelection": {"foo.vy": [output[0]]}},
3535
}
36+
if output[0] in ["bb", "bb_runtime", "cfg", "cfg_runtime"]:
37+
with pytest.raises(JSONError, match="experimentalCodegen not selected!"):
38+
_ = get_output_formats(input_json)
39+
else:
40+
assert get_output_formats(input_json) == {PurePath("foo.vy"): [output[1]]}
41+
42+
43+
@pytest.mark.parametrize("output", TRANSLATE_MAP.items())
44+
def test_translate_map_with_venom_flag(output):
45+
input_json = {
46+
"sources": {"foo.vy": ""},
47+
"settings": {"venomExperimental": True, "outputSelection": {"foo.vy": [output[0]]}},
48+
}
3649
assert get_output_formats(input_json) == {PurePath("foo.vy"): [output[1]]}
3750

3851

@@ -41,7 +54,23 @@ def test_star():
4154
"sources": {"foo.vy": "", "bar.vy": ""},
4255
"settings": {"outputSelection": {"*": ["*"]}},
4356
}
44-
expected = sorted(set(TRANSLATE_MAP.values()))
57+
translate_map = set(TRANSLATE_MAP.values())
58+
# if the venom flag is not present
59+
for k in VENOM_KEYS:
60+
translate_map.remove(k)
61+
62+
expected = sorted(translate_map)
63+
result = get_output_formats(input_json)
64+
assert result == {PurePath("foo.vy"): expected, PurePath("bar.vy"): expected}
65+
66+
67+
def test_star_with_venom_flag():
68+
input_json = {
69+
"sources": {"foo.vy": "", "bar.vy": ""},
70+
"settings": {"venomExperimental": True, "outputSelection": {"*": ["*"]}},
71+
}
72+
translate_map = set(TRANSLATE_MAP.values())
73+
expected = sorted(translate_map)
4574
result = get_output_formats(input_json)
4675
assert result == {PurePath("foo.vy"): expected, PurePath("bar.vy"): expected}
4776

vyper/cli/vyper_json.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@
3333
"metadata": "metadata",
3434
"layout": "layout",
3535
"userdoc": "userdoc",
36+
"bb": "bb",
37+
"bb_runtime": "bb_runtime",
38+
"cfg": "cfg",
39+
"cfg_runtime": "cfg_runtime",
3640
}
3741

42+
VENOM_KEYS = ("bb", "bb_runtime", "cfg", "cfg_runtime")
43+
3844

3945
def _parse_cli_args():
4046
return _parse_args(sys.argv[1:])
@@ -251,8 +257,15 @@ def get_output_formats(input_dict: dict) -> dict[PurePath, list[str]]:
251257
outputs.remove(key)
252258
outputs.update([i for i in TRANSLATE_MAP if i.startswith(key)])
253259

260+
should_output_venom = any(
261+
input_dict["settings"].get(alias, False)
262+
for alias in ("venomExperimental", "experimentalCodegen")
263+
)
264+
254265
if "*" in outputs:
255266
outputs = TRANSLATE_MAP.values()
267+
if not should_output_venom:
268+
outputs = [k for k in outputs if k not in VENOM_KEYS]
256269
else:
257270
try:
258271
outputs = [TRANSLATE_MAP[i] for i in outputs]
@@ -261,6 +274,12 @@ def get_output_formats(input_dict: dict) -> dict[PurePath, list[str]]:
261274

262275
outputs = sorted(list(outputs))
263276

277+
if not should_output_venom and any(k in outputs for k in VENOM_KEYS):
278+
selected_venom_keys = [k for k in outputs if k in VENOM_KEYS]
279+
raise JSONError(
280+
f"requested {selected_venom_keys} but experimentalCodegen not selected!"
281+
)
282+
264283
if path == "*":
265284
output_paths = [PurePath(path) for path in input_dict["sources"].keys()]
266285
else:
@@ -416,6 +435,18 @@ def format_to_output_dict(compiler_data: dict) -> dict:
416435
if "source_map_runtime" in data:
417436
evm["sourceMap"] = data["source_map_runtime"]
418437

438+
if any(i in data for i in VENOM_KEYS):
439+
venom = {}
440+
if "bb" in data:
441+
venom["bb"] = repr(data["bb"])
442+
if "bb_runtime" in data:
443+
venom["bb_runtime"] = repr(data["bb_runtime"])
444+
if "cfg" in data:
445+
venom["cfg"] = data["cfg"]
446+
if "cfg_runtime" in data:
447+
venom["cfg_runtime"] = data["cfg_runtime"]
448+
output_contracts["venom"] = venom
449+
419450
return output_dict
420451

421452

0 commit comments

Comments
 (0)