Skip to content

Commit

Permalink
feat[tool]: add source map for constructors (vyperlang#4008)
Browse files Browse the repository at this point in the history
this commit adds source map output for initcode
  • Loading branch information
tserg authored May 9, 2024
1 parent 4a0305a commit fb55f4c
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 20 deletions.
1 change: 1 addition & 0 deletions tests/unit/cli/vyper_compile/test_compile_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
13 changes: 8 additions & 5 deletions tests/unit/cli/vyper_json/test_compile_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
},
Expand Down Expand Up @@ -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):
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion vyper/cli/vyper_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,6 +53,7 @@
"abi",
"layout",
"source_map",
"source_map_runtime",
"method_identifiers",
"userdoc",
"devdoc",
Expand Down
18 changes: 9 additions & 9 deletions vyper/cli/vyper_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion vyper/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 15 additions & 4 deletions vyper/compiler/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand All @@ -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.
Expand Down

0 comments on commit fb55f4c

Please sign in to comment.