From a1fd228cb9936c3e4bbca6f3ee3fb4426ef45490 Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Mon, 8 Jan 2024 18:12:59 +0200 Subject: [PATCH] feat: add `bb` and `bb_runtime` output options (#3700) add `bb` and `bb_runtime` output options for dumping venom output. disable this output format in tests for now since many vyper contracts still will not compile to venom. --- tests/conftest.py | 43 +++++++++++++------ .../unit/cli/vyper_json/test_compile_json.py | 11 +++-- vyper/compiler/__init__.py | 4 ++ vyper/compiler/output.py | 8 ++++ vyper/compiler/phases.py | 8 +--- 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 51b4b4459a..e673f17b35 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -58,6 +58,14 @@ def pytest_addoption(parser): parser.addoption("--enable-compiler-debug-mode", action="store_true") +@pytest.fixture(scope="module") +def output_formats(): + output_formats = compiler.OUTPUT_FORMATS.copy() + del output_formats["bb"] + del output_formats["bb_runtime"] + return output_formats + + @pytest.fixture(scope="module") def optimize(pytestconfig): flag = pytestconfig.getoption("optimize") @@ -281,7 +289,14 @@ def ir_compiler(ir, *args, **kwargs): def _get_contract( - w3, source_code, optimize, *args, override_opt_level=None, input_bundle=None, **kwargs + w3, + source_code, + optimize, + output_formats, + *args, + override_opt_level=None, + input_bundle=None, + **kwargs, ): settings = Settings() settings.evm_version = kwargs.pop("evm_version", None) @@ -289,7 +304,7 @@ def _get_contract( out = compiler.compile_code( source_code, # test that all output formats can get generated - output_formats=list(compiler.OUTPUT_FORMATS.keys()), + output_formats=output_formats, settings=settings, input_bundle=input_bundle, show_gas_estimates=True, # Enable gas estimates for testing @@ -309,17 +324,17 @@ def _get_contract( @pytest.fixture(scope="module") -def get_contract(w3, optimize): +def get_contract(w3, optimize, output_formats): def fn(source_code, *args, **kwargs): - return _get_contract(w3, source_code, optimize, *args, **kwargs) + return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs) return fn @pytest.fixture -def get_contract_with_gas_estimation(tester, w3, optimize): +def get_contract_with_gas_estimation(tester, w3, optimize, output_formats): def get_contract_with_gas_estimation(source_code, *args, **kwargs): - contract = _get_contract(w3, source_code, optimize, *args, **kwargs) + contract = _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs) for abi_ in contract._classic_contract.functions.abi: if abi_["type"] == "function": set_decorator_to_contract_function(w3, tester, contract, source_code, abi_["name"]) @@ -329,15 +344,15 @@ def get_contract_with_gas_estimation(source_code, *args, **kwargs): @pytest.fixture -def get_contract_with_gas_estimation_for_constants(w3, optimize): +def get_contract_with_gas_estimation_for_constants(w3, optimize, output_formats): def get_contract_with_gas_estimation_for_constants(source_code, *args, **kwargs): - return _get_contract(w3, source_code, optimize, *args, **kwargs) + return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs) return get_contract_with_gas_estimation_for_constants @pytest.fixture(scope="module") -def get_contract_module(optimize): +def get_contract_module(optimize, output_formats): """ This fixture is used for Hypothesis tests to ensure that the same contract is called over multiple runs of the test. @@ -350,18 +365,18 @@ def get_contract_module(optimize): w3.eth.set_gas_price_strategy(zero_gas_price_strategy) def get_contract_module(source_code, *args, **kwargs): - return _get_contract(w3, source_code, optimize, *args, **kwargs) + return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs) return get_contract_module -def _deploy_blueprint_for(w3, source_code, optimize, initcode_prefix=b"", **kwargs): +def _deploy_blueprint_for(w3, source_code, optimize, output_formats, initcode_prefix=b"", **kwargs): settings = Settings() settings.evm_version = kwargs.pop("evm_version", None) settings.optimize = optimize out = compiler.compile_code( source_code, - output_formats=list(compiler.OUTPUT_FORMATS.keys()), + output_formats=output_formats, settings=settings, show_gas_estimates=True, # Enable gas estimates for testing ) @@ -394,9 +409,9 @@ def factory(address): @pytest.fixture(scope="module") -def deploy_blueprint_for(w3, optimize): +def deploy_blueprint_for(w3, optimize, output_formats): def deploy_blueprint_for(source_code, *args, **kwargs): - return _deploy_blueprint_for(w3, source_code, optimize, *args, **kwargs) + return _deploy_blueprint_for(w3, source_code, optimize, output_formats, *args, **kwargs) return deploy_blueprint_for diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index a50946ba21..c805e2b5b1 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -113,18 +113,23 @@ def test_keyerror_becomes_jsonerror(input_json): def test_compile_json(input_json, input_bundle): foo_input = input_bundle.load_file("contracts/foo.vy") + # remove bb and bb_runtime from output formats + # because they require venom (experimental) + output_formats = OUTPUT_FORMATS.copy() + del output_formats["bb"] + del output_formats["bb_runtime"] foo = compile_from_file_input( - foo_input, output_formats=OUTPUT_FORMATS, input_bundle=input_bundle + foo_input, output_formats=output_formats, input_bundle=input_bundle ) library_input = input_bundle.load_file("contracts/library.vy") library = compile_from_file_input( - library_input, output_formats=OUTPUT_FORMATS, input_bundle=input_bundle + library_input, output_formats=output_formats, input_bundle=input_bundle ) bar_input = input_bundle.load_file("contracts/bar.vy") bar = compile_from_file_input( - bar_input, output_formats=OUTPUT_FORMATS, input_bundle=input_bundle + bar_input, output_formats=output_formats, input_bundle=input_bundle ) compile_code_results = { diff --git a/vyper/compiler/__init__.py b/vyper/compiler/__init__.py index 0f7d7a8014..9297f9e3c3 100644 --- a/vyper/compiler/__init__.py +++ b/vyper/compiler/__init__.py @@ -23,6 +23,8 @@ # requires ir_node "external_interface": output.build_external_interface_output, "interface": output.build_interface_output, + "bb": output.build_bb_output, + "bb_runtime": output.build_bb_runtime_output, "ir": output.build_ir_output, "ir_runtime": output.build_ir_runtime_output, "ir_dict": output.build_ir_dict_output, @@ -84,6 +86,8 @@ def compile_from_file_input( two arguments - the name of the contract, and the exception that was raised no_bytecode_metadata: bool, optional Do not add metadata to bytecode. Defaults to False + experimental_codegen: bool + Use experimental codegen. Defaults to False Returns ------- diff --git a/vyper/compiler/output.py b/vyper/compiler/output.py index 8ccf6abee1..5e11a20139 100644 --- a/vyper/compiler/output.py +++ b/vyper/compiler/output.py @@ -84,6 +84,14 @@ def build_interface_output(compiler_data: CompilerData) -> str: return out +def build_bb_output(compiler_data: CompilerData) -> IRnode: + return compiler_data.venom_functions[0] + + +def build_bb_runtime_output(compiler_data: CompilerData) -> IRnode: + return compiler_data.venom_functions[1] + + def build_ir_output(compiler_data: CompilerData) -> IRnode: if compiler_data.show_gas_estimates: IRnode.repr_show_gas = True diff --git a/vyper/compiler/phases.py b/vyper/compiler/phases.py index 850adcfea3..ba6ccbda20 100644 --- a/vyper/compiler/phases.py +++ b/vyper/compiler/phases.py @@ -174,9 +174,7 @@ def global_ctx(self) -> ModuleT: @cached_property def _ir_output(self): # fetch both deployment and runtime IR - return generate_ir_nodes( - self.global_ctx, self.settings.optimize, self.settings.experimental_codegen - ) + return generate_ir_nodes(self.global_ctx, self.settings.optimize) @property def ir_nodes(self) -> IRnode: @@ -272,9 +270,7 @@ def generate_annotated_ast( return vyper_module, symbol_tables -def generate_ir_nodes( - global_ctx: ModuleT, optimize: OptimizationLevel, experimental_codegen: bool -) -> tuple[IRnode, IRnode]: +def generate_ir_nodes(global_ctx: ModuleT, optimize: OptimizationLevel) -> tuple[IRnode, IRnode]: """ Generate the intermediate representation (IR) from the contextualized AST.