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
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
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
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
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
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
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
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