From fb55f4c79654074e1abe9d202539366684c77b00 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Fri, 10 May 2024 06:20:41 +0800 Subject: [PATCH] feat[tool]: add source map for constructors (#4008) this commit adds source map output for initcode --- .../cli/vyper_compile/test_compile_files.py | 1 + .../unit/cli/vyper_json/test_compile_json.py | 13 ++++++++----- vyper/cli/vyper_compile.py | 4 +++- vyper/cli/vyper_json.py | 18 +++++++++--------- vyper/compiler/__init__.py | 2 +- vyper/compiler/output.py | 19 +++++++++++++++---- 6 files changed, 37 insertions(+), 20 deletions(-) diff --git a/tests/unit/cli/vyper_compile/test_compile_files.py b/tests/unit/cli/vyper_compile/test_compile_files.py index 6467ff6dc9..3856aa3362 100644 --- a/tests/unit/cli/vyper_compile/test_compile_files.py +++ b/tests/unit/cli/vyper_compile/test_compile_files.py @@ -22,6 +22,7 @@ def test_combined_json_keys(chdir_tmp_path, make_file): "blueprint_bytecode", "abi", "source_map", + "source_map_runtime", "layout", "method_identifiers", "userdoc", diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index f4c93c08bf..ef3284cd15 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -171,12 +171,15 @@ def test_compile_json(input_json, input_bundle): "userdoc": data["userdoc"], "metadata": data["metadata"], "evm": { - "bytecode": {"object": data["bytecode"], "opcodes": data["opcodes"]}, + "bytecode": { + "object": data["bytecode"], + "opcodes": data["opcodes"], + "sourceMap": data["source_map"], + }, "deployedBytecode": { "object": data["bytecode_runtime"], "opcodes": data["opcodes_runtime"], - "sourceMap": data["source_map"]["pc_pos_map_compressed"], - "sourceMapFull": data["source_map_full"], + "sourceMap": data["source_map_runtime"], }, "methodIdentifiers": data["method_identifiers"], }, @@ -266,7 +269,7 @@ def test_exc_handler_to_dict_compiler(input_json): def test_source_ids_increment(input_json): - input_json["settings"]["outputSelection"] = {"*": ["ast", "evm.deployedBytecode.sourceMapFull"]} + input_json["settings"]["outputSelection"] = {"*": ["ast", "evm.deployedBytecode.sourceMap"]} result = compile_json(input_json) def get(filename, contractname): @@ -275,7 +278,7 @@ def get(filename, contractname): # grab it via source map to sanity check contract_info = result["contracts"][filename][contractname]["evm"] - pc_ast_map = contract_info["deployedBytecode"]["sourceMapFull"]["pc_ast_map"] + pc_ast_map = contract_info["deployedBytecode"]["sourceMap"]["pc_ast_map"] pc_item = next(iter(pc_ast_map.values())) source_id, node_id = pc_item assert ret == source_id diff --git a/vyper/cli/vyper_compile.py b/vyper/cli/vyper_compile.py index bb2cfa34b8..226a76242a 100755 --- a/vyper/cli/vyper_compile.py +++ b/vyper/cli/vyper_compile.py @@ -24,7 +24,8 @@ blueprint_bytecode - Deployment bytecode for an ERC-5202 compatible blueprint abi - ABI in JSON format abi_python - ABI in python format -source_map - Vyper source map +source_map - Vyper source map of deployable bytecode +source_map_runtime - Vyper source map of runtime bytecode method_identifiers - Dictionary of method signature to method identifier userdoc - Natspec user documentation devdoc - Natspec developer documentation @@ -52,6 +53,7 @@ "abi", "layout", "source_map", + "source_map_runtime", "method_identifiers", "userdoc", "devdoc", diff --git a/vyper/cli/vyper_json.py b/vyper/cli/vyper_json.py index 42b017fb94..4f73732687 100755 --- a/vyper/cli/vyper_json.py +++ b/vyper/cli/vyper_json.py @@ -22,10 +22,10 @@ "evm.methodIdentifiers": "method_identifiers", "evm.bytecode.object": "bytecode", "evm.bytecode.opcodes": "opcodes", + "evm.bytecode.sourceMap": "source_map", "evm.deployedBytecode.object": "bytecode_runtime", "evm.deployedBytecode.opcodes": "opcodes_runtime", - "evm.deployedBytecode.sourceMap": "source_map", - "evm.deployedBytecode.sourceMapFull": "source_map_full", + "evm.deployedBytecode.sourceMap": "source_map_runtime", "interface": "interface", "ir": "ir_dict", "ir_runtime": "ir_runtime_dict", @@ -341,24 +341,24 @@ def format_to_output_dict(compiler_data: dict) -> dict: output_contracts["evm"] = {"methodIdentifiers": data["method_identifiers"]} evm_keys = ("bytecode", "opcodes") - if any(i in data for i in evm_keys): + pc_maps_keys = ("source_map",) + if any(i in data for i in evm_keys + pc_maps_keys): evm = output_contracts.setdefault("evm", {}).setdefault("bytecode", {}) if "bytecode" in data: evm["object"] = data["bytecode"] if "opcodes" in data: evm["opcodes"] = data["opcodes"] + if "source_map" in data: + evm["sourceMap"] = data["source_map"] - pc_maps_keys = ("source_map", "source_map_full") - if any(i + "_runtime" in data for i in evm_keys) or any(i in data for i in pc_maps_keys): + if any(i + "_runtime" in data for i in evm_keys + pc_maps_keys): evm = output_contracts.setdefault("evm", {}).setdefault("deployedBytecode", {}) if "bytecode_runtime" in data: evm["object"] = data["bytecode_runtime"] if "opcodes_runtime" in data: evm["opcodes"] = data["opcodes_runtime"] - if "source_map" in data: - evm["sourceMap"] = data["source_map"]["pc_pos_map_compressed"] - if "source_map_full" in data: - evm["sourceMapFull"] = data["source_map_full"] + if "source_map_runtime" in data: + evm["sourceMap"] = data["source_map_runtime"] return output_dict diff --git a/vyper/compiler/__init__.py b/vyper/compiler/__init__.py index 26439d2918..9ed38885b4 100644 --- a/vyper/compiler/__init__.py +++ b/vyper/compiler/__init__.py @@ -37,7 +37,7 @@ "abi": output.build_abi_output, "asm": output.build_asm_output, "source_map": output.build_source_map_output, - "source_map_full": output.build_source_map_output, + "source_map_runtime": output.build_source_map_runtime_output, # requires bytecode "bytecode": output.build_bytecode_output, "bytecode_runtime": output.build_bytecode_runtime_output, diff --git a/vyper/compiler/output.py b/vyper/compiler/output.py index c9b138ba64..577afd3822 100644 --- a/vyper/compiler/output.py +++ b/vyper/compiler/output.py @@ -288,16 +288,13 @@ def _build_node_identifier(ast_node): return (ast_node.module_node.source_id, ast_node.node_id) -def build_source_map_output(compiler_data: CompilerData) -> dict: +def _build_source_map_output(compiler_data, bytecode, pc_maps): """ Generate source map output in various formats. Note that integrations are encouraged to use pc_ast_map since the information it provides is a superset of the other formats, and the other types are included for legacy reasons. """ - bytecode, pc_maps = compile_ir.assembly_to_evm( - compiler_data.assembly_runtime, insert_compiler_metadata=False - ) # sort the pc maps alphabetically # CMC 2024-03-09 is this really necessary? out = {} @@ -322,6 +319,20 @@ def build_source_map_output(compiler_data: CompilerData) -> dict: return out +def build_source_map_output(compiler_data: CompilerData) -> dict: + bytecode, pc_maps = compile_ir.assembly_to_evm( + compiler_data.assembly, insert_compiler_metadata=False + ) + return _build_source_map_output(compiler_data, bytecode, pc_maps) + + +def build_source_map_runtime_output(compiler_data: CompilerData) -> dict: + bytecode, pc_maps = compile_ir.assembly_to_evm( + compiler_data.assembly_runtime, insert_compiler_metadata=False + ) + return _build_source_map_output(compiler_data, bytecode, pc_maps) + + # generate a solidity-style source map. this functionality is deprecated # in favor of pc_ast_map, and may not be maintained to the same level # as pc_ast_map.