Exemple #1
0
def get_interface_codes(root_path: Path, contract_sources: ContractCodes) -> Dict:
    interface_codes: Dict = {}
    interfaces: Dict = {}

    for file_path, code in contract_sources.items():
        interfaces[file_path] = {}
        parent_path = root_path.joinpath(file_path).parent

        interface_codes = extract_file_interface_imports(code)
        for interface_name, interface_path in interface_codes.items():

            base_paths = [parent_path]
            if not interface_path.startswith('.') and root_path.joinpath(file_path).exists():
                base_paths.append(root_path)
            elif interface_path.startswith('../') and parent_path == root_path:
                raise FileNotFoundError(
                    f"{file_path} - Cannot perform relative import outside of base folder"
                )

            valid_path = get_interface_file_path(base_paths, interface_path)
            with valid_path.open() as fh:
                code = fh.read()
                if valid_path.suffix == '.json':
                    interfaces[file_path][interface_name] = {
                        'type': 'json',
                        'code': json.loads(code.encode())
                    }
                else:
                    interfaces[file_path][interface_name] = {
                        'type': 'vyper',
                        'code': code
                    }

    return interfaces
Exemple #2
0
def get_input_dict_output_formats(input_dict: Dict, contract_sources: ContractCodes) -> Dict:
    output_formats = {}
    for path, outputs in input_dict['outputSelection'].items():
        if isinstance(outputs, dict):
            # if outputs are given in solc json format, collapse them into a single list
            outputs = set(x for i in outputs.values() for x in i)
        else:
            outputs = set(outputs)

        for key in [i for i in ('evm', 'evm.bytecode', 'evm.deployedBytecode') if i in outputs]:
            outputs.remove(key)
            outputs.update([i for i in TRANSLATE_MAP if i.startswith(key)])
        if '*' in outputs:
            outputs = sorted(TRANSLATE_MAP.values())
        else:
            try:
                outputs = sorted(TRANSLATE_MAP[i] for i in outputs)
            except KeyError as e:
                raise JSONError(f"Invalid outputSelection - {e}")

        if path == "*":
            output_keys = list(contract_sources.keys())
        else:
            output_keys = [_standardize_path(path)]
            if output_keys[0] not in contract_sources:
                raise JSONError(f"outputSelection references unknown contract '{output_keys[0]}'")

        for key in output_keys:
            output_formats[key] = outputs

    return output_formats
Exemple #3
0
def get_interface_codes(root_path: Path, contract_sources: ContractCodes) -> Dict:
    interface_codes: Dict = {}
    interfaces: Dict = {}

    for file_path, code in contract_sources.items():
        interfaces[file_path] = {}
        parent_path = root_path.joinpath(file_path).parent

        interface_codes = extract_file_interface_imports(code)
        for interface_name, interface_path in interface_codes.items():

            base_paths = [parent_path]
            if not interface_path.startswith(".") and root_path.joinpath(file_path).exists():
                base_paths.append(root_path)
            elif interface_path.startswith("../") and len(Path(file_path).parent.parts) < Path(
                interface_path
            ).parts.count(".."):
                raise FileNotFoundError(
                    f"{file_path} - Cannot perform relative import outside of base folder"
                )

            valid_path = get_interface_file_path(base_paths, interface_path)
            with valid_path.open() as fh:
                code = fh.read()
                if valid_path.suffix == ".json":
                    interfaces[file_path][interface_name] = {
                        "type": "json",
                        "code": json.loads(code.encode()),
                    }
                else:
                    interfaces[file_path][interface_name] = {"type": "vyper", "code": code}

    return interfaces
Exemple #4
0
def get_interface_codes(root_path: Path, contract_sources: ContractCodes) -> Dict:
    interface_codes: Dict = {}
    interfaces: Dict = {}

    for file_path, code in contract_sources.items():
        interfaces[file_path] = {}
        parent_path = root_path.joinpath(file_path).parent

        interface_codes = extract_file_interface_imports(code)
        for interface_name, interface_path in interface_codes.items():

            base_paths = [parent_path]
            if not interface_path.startswith(".") and root_path.joinpath(file_path).exists():
                base_paths.append(root_path)
            elif interface_path.startswith("../") and len(Path(file_path).parent.parts) < Path(
                interface_path
            ).parts.count(".."):
                raise FileNotFoundError(
                    f"{file_path} - Cannot perform relative import outside of base folder"
                )

            valid_path = get_interface_file_path(base_paths, interface_path)
            with valid_path.open() as fh:
                code = fh.read()
                if valid_path.suffix == ".json":
                    contents = json.loads(code.encode())

                    # EthPM Manifest (EIP-2678)
                    if "contractTypes" in contents:
                        if (
                            interface_name not in contents["contractTypes"]
                            or "abi" not in contents["contractTypes"][interface_name]
                        ):
                            raise ValueError(
                                f"Could not find interface '{interface_name}'"
                                f" in manifest '{valid_path}'."
                            )

                        interfaces[file_path][interface_name] = {
                            "type": "json",
                            "code": contents["contractTypes"][interface_name]["abi"],
                        }

                    # ABI JSON file (either `List[ABI]` or `{"abi": List[ABI]}`)
                    elif isinstance(contents, list) or (
                        "abi" in contents and isinstance(contents["abi"], list)
                    ):
                        interfaces[file_path][interface_name] = {"type": "json", "code": contents}

                    else:
                        raise ValueError(f"Corrupted file: '{valid_path}'")

                else:
                    interfaces[file_path][interface_name] = {"type": "vyper", "code": code}

    return interfaces
Exemple #5
0
def compile_codes(contract_sources: ContractCodes,
                  output_formats: Union[OutputDict, OutputFormats,
                                        None] = None,
                  exc_handler: Union[Callable, None] = None,
                  interface_codes: Union[InterfaceDict, InterfaceImports,
                                         None] = None,
                  initial_id: int = 0) -> OrderedDict:

    if output_formats is None:
        output_formats = ('bytecode', )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        code = contract_sources[contract_name]
        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:
                interfaces: Any = interface_codes
                if (isinstance(interfaces, dict)
                        and contract_name in interfaces
                        and isinstance(interfaces[contract_name], dict)):
                    interfaces = interfaces[contract_name]
                out.setdefault(contract_name, {})
                out[contract_name][output_format] = OUTPUT_FORMATS[
                    output_format](
                        # trailing newline fixes python parsing bug when source ends in a comment
                        # https://bugs.python.org/issue35107
                        code=f"{code}\n",
                        contract_name=contract_name,
                        interface_codes=interfaces,
                        source_id=source_id)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out
Exemple #6
0
def compile_codes(contract_sources: ContractCodes,
                  output_formats: Union[OutputDict, OutputFormats,
                                        None] = None,
                  exc_handler: Union[Callable, None] = None,
                  interface_codes: Union[InterfaceDict, InterfaceImports,
                                         None] = None,
                  initial_id: int = 0) -> OrderedDict:

    if output_formats is None:
        output_formats = ('bytecode', )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        code = contract_sources[contract_name]
        for output_format in output_formats[contract_name]:
            if output_format not in output_formats_map:
                raise ValueError(
                    f'Unsupported format type {repr(output_format)}')

            try:
                interfaces: Any = interface_codes
                if (isinstance(interfaces, dict)
                        and contract_name in interfaces
                        and isinstance(interfaces[contract_name], dict)):
                    interfaces = interfaces[contract_name]
                out.setdefault(contract_name, {})
                out[contract_name][output_format] = output_formats_map[
                    output_format](code=code,
                                   contract_name=contract_name,
                                   interface_codes=interfaces,
                                   source_id=source_id)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out
Exemple #7
0
def compile_codes(
    contract_sources: ContractCodes,
    output_formats: Union[OutputDict, OutputFormats, None] = None,
    exc_handler: Union[Callable, None] = None,
    interface_codes: Union[InterfaceDict, InterfaceImports, None] = None,
    initial_id: int = 0,
) -> OrderedDict:
    """
    Generate compiler output(s) from one or more contract source codes.

    Arguments
    ---------
    contract_sources: Dict[str, str]
        Vyper source codes to be compiled. Formatted as `{"contract name": "source code"}`
    output_formats: List, optional
        List of compiler outputs to generate. Possible options are all the keys
        in `OUTPUT_FORMATS`. If not given, the deployment bytecode is generated.
    exc_handler: Callable, optional
        Callable used to handle exceptions if the compilation fails. Should accept
        two arguments - the name of the contract, and the exception that was raised
    initial_id: int, optional
        The lowest source ID value to be used when generating the source map.
    evm_version: str, optional
        The target EVM ruleset to compile for. If not given, defaults to the latest
        implemented ruleset.
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts during compilation.

        * May be a singular dictionary shared across all sources to be compiled,
          i.e. `{'interface name': "definition"}`
        * or may be organized according to contracts that are being compiled, i.e.
          `{'contract name': {'interface name': "definition"}`

        * Interface definitions are formatted as: `{'type': "json/vyper", 'code': "interface code"}`
        * JSON interfaces are given as lists, vyper interfaces as strings

    Returns
    -------
    Dict
        Compiler output as `{'contract name': {'output key': "output data"}}`
    """

    if output_formats is None:
        output_formats = ("bytecode", )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        # trailing newline fixes python parsing bug when source ends in a comment
        # https://bugs.python.org/issue35107
        source_code = f"{contract_sources[contract_name]}\n"
        interfaces: Any = interface_codes
        if (isinstance(interfaces, dict) and contract_name in interfaces
                and isinstance(interfaces[contract_name], dict)):
            interfaces = interfaces[contract_name]

        compiler_data = CompilerData(source_code, contract_name, interfaces,
                                     source_id)
        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, {})
                out[contract_name][output_format] = OUTPUT_FORMATS[
                    output_format](compiler_data)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out
Exemple #8
0
def compile_codes(
    contract_sources: ContractCodes,
    output_formats: Union[OutputDict, OutputFormats, None] = None,
    exc_handler: Union[Callable, None] = None,
    interface_codes: Union[InterfaceDict, InterfaceImports, None] = None,
    initial_id: int = 0,
    no_optimize: bool = False,
    storage_layouts: Dict[ContractPath, StorageLayout] = None,
    show_gas_estimates: bool = False,
) -> OrderedDict:
    """
    Generate compiler output(s) from one or more contract source codes.

    Arguments
    ---------
    contract_sources: Dict[str, str]
        Vyper source codes to be compiled. Formatted as `{"contract name": "source code"}`
    output_formats: List, optional
        List of compiler outputs to generate. Possible options are all the keys
        in `OUTPUT_FORMATS`. If not given, the deployment bytecode is generated.
    exc_handler: Callable, optional
        Callable used to handle exceptions if the compilation fails. Should accept
        two arguments - the name of the contract, and the exception that was raised
    initial_id: int, optional
        The lowest source ID value to be used when generating the source map.
    evm_version: str, optional
        The target EVM ruleset to compile for. If not given, defaults to the latest
        implemented ruleset.
    no_optimize: bool, optional
        Turn off optimizations. Defaults to False
    show_gas_estimates: bool, optional
        Show gas estimates for abi and ir output modes
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts during compilation.

        * May be a singular dictionary shared across all sources to be compiled,
          i.e. `{'interface name': "definition"}`
        * or may be organized according to contracts that are being compiled, i.e.
          `{'contract name': {'interface name': "definition"}`

        * Interface definitions are formatted as: `{'type': "json/vyper", 'code': "interface code"}`
        * JSON interfaces are given as lists, vyper interfaces as strings

    Returns
    -------
    Dict
        Compiler output as `{'contract name': {'output key': "output data"}}`
    """

    if output_formats is None:
        output_formats = ("bytecode", )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        source_code = contract_sources[contract_name]
        interfaces: Any = interface_codes
        storage_layout_override = None
        if storage_layouts and contract_name in storage_layouts:
            storage_layout_override = storage_layouts[contract_name]

        if (isinstance(interfaces, dict) and contract_name in interfaces
                and isinstance(interfaces[contract_name], dict)):
            interfaces = interfaces[contract_name]

        # make IR output the same between runs
        codegen.reset_names()
        compiler_data = CompilerData(
            source_code,
            contract_name,
            interfaces,
            source_id,
            no_optimize,
            storage_layout_override,
            show_gas_estimates,
        )
        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, {})
                out[contract_name][output_format] = OUTPUT_FORMATS[
                    output_format](compiler_data)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out