Skip to content

Commit

Permalink
fix evm version passing to compiler data again
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper committed Oct 1, 2023
1 parent 946f2cf commit 336bb50
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 18 deletions.
6 changes: 2 additions & 4 deletions vyper/compiler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,9 @@ for specific implementation details.
[`vyper.compiler.compile_codes`](__init__.py) is the main user-facing function for
generating compiler output from Vyper source. The process is as follows:

1. The `@evm_wrapper` decorator sets the target EVM version in
[`opcodes.py`](../evm/opcodes.py).
2. A [`CompilerData`](phases.py) object is created for each contract to be compiled.
1. A [`CompilerData`](phases.py) object is created for each contract to be compiled.
This object uses `@property` methods to trigger phases of the compiler as required.
3. Functions in [`output.py`](output.py) generate the requested outputs from the
2. Functions in [`output.py`](output.py) generate the requested outputs from the
compiler data.

## Design
Expand Down
26 changes: 12 additions & 14 deletions vyper/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,18 @@ def compile_codes(
show_gas_estimates,
no_bytecode_metadata,
)
_ = compiler_data._generate_ast
with anchor_evm_version(compiler_data.settings.evm_version):
for output_format in output_formats[contract_name]:
if output_format not in OUTPUT_FORMATS:
raise ValueError(f"Unsupported format type {repr(output_format)}")
try:
out.setdefault(contract_name, {})
formatter = OUTPUT_FORMATS[output_format]
out[contract_name][output_format] = formatter(compiler_data)
except Exception as exc:
if exc_handler is not None:
exc_handler(contract_name, exc)
else:
raise exc
for output_format in output_formats[contract_name]:
if output_format not in OUTPUT_FORMATS:
raise ValueError(f"Unsupported format type {repr(output_format)}")
try:
out.setdefault(contract_name, {})
formatter = OUTPUT_FORMATS[output_format]
out[contract_name][output_format] = formatter(compiler_data)
except Exception as exc:
if exc_handler is not None:
exc_handler(contract_name, exc)
else:
raise exc

return out

Expand Down
27 changes: 27 additions & 0 deletions vyper/compiler/phases.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import functools

Check notice

Code scanning / CodeQL

Module is imported with 'import' and 'import from' Note

Module 'functools' is imported with both 'import' and 'import from'.
import warnings
from functools import cached_property
from typing import Optional, Tuple
Expand All @@ -9,13 +10,23 @@
from vyper.codegen.global_context import GlobalContext
from vyper.codegen.ir_node import IRnode
from vyper.compiler.settings import OptimizationLevel, Settings
from vyper.evm.opcodes import anchor_evm_version
from vyper.exceptions import StructureException
from vyper.ir import compile_ir, optimizer
from vyper.semantics import set_data_positions, validate_semantics
from vyper.semantics.types.function import ContractFunctionT
from vyper.typing import InterfaceImports, StorageLayout


def _evm_wrapper(fn):
@functools.wraps(fn)
def inner(self, *args, **kwargs):
with anchor_evm_version(self.settings.evm_version):
return fn(self, *args, **kwargs)

return inner


class CompilerData:
"""
Object for fetching and storing compiler data for a Vyper contract.
Expand Down Expand Up @@ -88,6 +99,8 @@ def __init__(
self.no_bytecode_metadata = no_bytecode_metadata
self.settings = settings or Settings()

_ = self._generate_ast # force settings to be calculated

@cached_property
def _generate_ast(self):
settings, ast = generate_ast(self.source_code, self.source_id, self.contract_name)
Expand Down Expand Up @@ -125,48 +138,57 @@ def vyper_module(self):
return self._generate_ast

@cached_property
@_evm_wrapper
def vyper_module_unfolded(self) -> vy_ast.Module:
# This phase is intended to generate an AST for tooling use, and is not
# used in the compilation process.

return generate_unfolded_ast(self.vyper_module, self.interface_codes)

@cached_property
@_evm_wrapper
def _folded_module(self):
return generate_folded_ast(
self.vyper_module, self.interface_codes, self.storage_layout_override
)

@property
@_evm_wrapper
def vyper_module_folded(self) -> vy_ast.Module:
module, storage_layout = self._folded_module
return module

@property
@_evm_wrapper
def storage_layout(self) -> StorageLayout:
module, storage_layout = self._folded_module
return storage_layout

@property
@_evm_wrapper
def global_ctx(self) -> GlobalContext:
return GlobalContext(self.vyper_module_folded)

@cached_property
@_evm_wrapper
def _ir_output(self):
# fetch both deployment and runtime IR
return generate_ir_nodes(self.global_ctx, self.settings.optimize)

@property
@_evm_wrapper
def ir_nodes(self) -> IRnode:
ir, ir_runtime = self._ir_output
return ir

@property
@_evm_wrapper
def ir_runtime(self) -> IRnode:
ir, ir_runtime = self._ir_output
return ir_runtime

@property
@_evm_wrapper
def function_signatures(self) -> dict[str, ContractFunctionT]:
# some metadata gets calculated during codegen, so
# ensure codegen is run:
Expand All @@ -176,23 +198,28 @@ def function_signatures(self) -> dict[str, ContractFunctionT]:
return {f.name: f._metadata["type"] for f in fs}

@cached_property
@_evm_wrapper
def assembly(self) -> list:
return generate_assembly(self.ir_nodes, self.settings.optimize)

@cached_property
@_evm_wrapper
def assembly_runtime(self) -> list:
return generate_assembly(self.ir_runtime, self.settings.optimize)

@cached_property
@_evm_wrapper
def bytecode(self) -> bytes:
insert_compiler_metadata = not self.no_bytecode_metadata
return generate_bytecode(self.assembly, insert_compiler_metadata=insert_compiler_metadata)

@cached_property
@_evm_wrapper
def bytecode_runtime(self) -> bytes:
return generate_bytecode(self.assembly_runtime, insert_compiler_metadata=False)

@cached_property
@_evm_wrapper
def blueprint_bytecode(self) -> bytes:
blueprint_preamble = b"\xFE\x71\x00" # ERC5202 preamble
blueprint_bytecode = blueprint_preamble + self.bytecode
Expand Down

0 comments on commit 336bb50

Please sign in to comment.