Skip to content

Commit

Permalink
add vyper signature to bytecode (#2860)
Browse files Browse the repository at this point in the history
add a vyper signature to vyper bytecode. this makes it easier to
identify on block explorers. the format is the CBOR encoding of
`{"vyper": (major,minor,patch)}`. for instance, a vyper 0.3.4
signature will be: `b"\xa1\x65vyper\x83\x00\x03\x04"`
  • Loading branch information
charles-cooper authored May 23, 2022
1 parent 1b0521b commit 8d86995
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 8 deletions.
4 changes: 3 additions & 1 deletion vyper/compiler/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ def _build_asm(asm_list):


def build_source_map_output(compiler_data: CompilerData) -> OrderedDict:
_, line_number_map = compile_ir.assembly_to_evm(compiler_data.assembly_runtime)
_, line_number_map = compile_ir.assembly_to_evm(
compiler_data.assembly_runtime, insert_vyper_signature=True
)
# Sort line_number_map
out = OrderedDict()
for k in sorted(line_number_map.keys()):
Expand Down
8 changes: 4 additions & 4 deletions vyper/compiler/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,13 @@ def assembly_runtime(self) -> list:
@property
def bytecode(self) -> bytes:
if not hasattr(self, "_bytecode"):
self._bytecode = generate_bytecode(self.assembly)
self._bytecode = generate_bytecode(self.assembly, is_runtime=False)
return self._bytecode

@property
def bytecode_runtime(self) -> bytes:
if not hasattr(self, "_bytecode_runtime"):
self._bytecode_runtime = generate_bytecode(self.assembly_runtime)
self._bytecode_runtime = generate_bytecode(self.assembly_runtime, is_runtime=True)
return self._bytecode_runtime


Expand Down Expand Up @@ -323,7 +323,7 @@ def _find_nested_opcode(assembly, key):
return any(_find_nested_opcode(x, key) for x in sublists)


def generate_bytecode(assembly: list) -> bytes:
def generate_bytecode(assembly: list, is_runtime: bool = False) -> bytes:
"""
Generate bytecode from assembly instructions.
Expand All @@ -337,4 +337,4 @@ def generate_bytecode(assembly: list) -> bytes:
bytes
Final compiled bytecode.
"""
return compile_ir.assembly_to_evm(assembly)[0]
return compile_ir.assembly_to_evm(assembly, insert_vyper_signature=is_runtime)[0]
19 changes: 16 additions & 3 deletions vyper/ir/compile_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from vyper.evm.opcodes import get_opcodes
from vyper.exceptions import CodegenPanic, CompilerPanic
from vyper.utils import MemoryPositions
from vyper.version import version_tuple

PUSH_OFFSET = 0x5F
DUP_OFFSET = 0x7F
Expand Down Expand Up @@ -507,7 +508,7 @@ def _height_of(witharg):
o.extend(["_sym_subcode_size", begincode, "_mem_deploy_start", "CODECOPY"])

# calculate the len of runtime code
o.extend(["_sym_subcode_size"] + PUSH(padding) + ["ADD"]) # stack: len
o.extend(["_OFST", "_sym_subcode_size", padding]) # stack: len
o.extend(["_mem_deploy_start"]) # stack: len mem_ofst
o.extend(["RETURN"])

Expand Down Expand Up @@ -918,7 +919,7 @@ def _optimize_assembly(assembly):


# Assembles assembly into EVM
def assembly_to_evm(assembly, start_pos=0):
def assembly_to_evm(assembly, start_pos=0, insert_vyper_signature=False):
line_number_map = {
"breakpoints": set(),
"pc_breakpoints": set(),
Expand All @@ -930,6 +931,11 @@ def assembly_to_evm(assembly, start_pos=0):
runtime_code, runtime_code_start, runtime_code_end = None, None, None
pos = start_pos

bytecode_suffix = b""
if insert_vyper_signature:
# CBOR encoded: {"vyper": [major,minor,patch]}
bytecode_suffix += b"\xa1\x65vyper\x83" + bytes(list(version_tuple))

# go through the code, resolving symbolic locations
# (i.e. JUMPDEST locations) to actual code locations
for i, item in enumerate(assembly):
Expand Down Expand Up @@ -977,7 +983,10 @@ def assembly_to_evm(assembly, start_pos=0):
pos += 0
elif isinstance(item, list):
assert runtime_code is None, "Multiple subcodes"
runtime_code, sub_map = assembly_to_evm(item, start_pos=pos)
runtime_code, sub_map = assembly_to_evm(
item, start_pos=pos, insert_vyper_signature=True
)

assert item[0].startswith("_DEPLOY_MEM_OFST_")
ctor_mem_size = int(item[0][len("_DEPLOY_MEM_OFST_") :])

Expand All @@ -991,6 +1000,8 @@ def assembly_to_evm(assembly, start_pos=0):
else:
pos += 1

pos += len(bytecode_suffix)

code_end = pos - start_pos
posmap["_sym_code_end"] = code_end
posmap["_mem_deploy_start"] = runtime_code_start
Expand Down Expand Up @@ -1045,6 +1056,8 @@ def assembly_to_evm(assembly, start_pos=0):
# Should never reach because, assembly is create in _compile_to_assembly.
raise Exception("Weird symbol in assembly: " + str(item)) # pragma: no cover

o += bytecode_suffix

assert len(o) == pos - start_pos, (len(o), pos, start_pos)
line_number_map["breakpoints"] = list(line_number_map["breakpoints"])
line_number_map["pc_breakpoints"] = list(line_number_map["pc_breakpoints"])
Expand Down

0 comments on commit 8d86995

Please sign in to comment.