def validate_single_matching_uri(all_blockchain_uris: List[str], w3: Web3) -> str: """ Return a single block URI after validating that it is the *only* URI in all_blockchain_uris that matches the w3 instance. """ matching_uris = [ uri for uri in all_blockchain_uris if check_if_chain_matches_chain_uri(w3, uri) ] if not matching_uris: raise ValidationError("Package has no matching URIs on chain.") elif len(matching_uris) != 1: raise ValidationError( f"Package has too many ({len(matching_uris)}) matching URIs: {matching_uris}." ) return matching_uris[0]
def validate_link_ref(offset: int, length: int, bytecode: str) -> str: slot_length = offset + length slot = bytecode[offset:slot_length] if slot[:2] != "__" and slot[-2:] != "__": raise ValidationError( f"Slot: {slot}, at offset: {offset} of length: {length} is not a valid " "link_ref that can be replaced." ) return bytecode
def fetch_uri_contents(self, uri: str) -> bytes: ipfs_hash = extract_ipfs_path_from_uri(uri) contents = self.client.cat(ipfs_hash) validation_hash = generate_file_hash(contents) if validation_hash != ipfs_hash: raise ValidationError( f"Hashed IPFS contents retrieved from uri: {uri} do not match its content hash." ) return contents
def validate_package_against_schema(package_data: Dict[str, Any]) -> None: """ Load and validate package json against schema located at RELEASE_PACKAGE_SCHEMA_PATH. """ schema_data = _load_schema_data() try: validate(package_data, schema_data) except jsonValidationError: raise ValidationError("Package:{0} invalid for schema:{1}".format( package_data, RELEASE_PACKAGE_SCHEMA_PATH))
def validate_registry_uri_authority(auth: str) -> None: """ Raise an exception if the authority is not a valid ENS domain or a valid checksummed contract address. """ try: address, chain_id = auth.split(':') except ValueError: raise ValidationError(f"{auth} is not a valid registry URI authority. " "Please try again with a valid registry URI.") if is_ens_domain(address) is False and not is_checksum_address(address): raise ValidationError(f"{address} is not a valid registry address. " "Please try again with a valid registry URI.") if not is_supported_chain_id(to_int(text=chain_id)): raise ValidationError( f"Chain ID: {chain_id} is not supported. Supported chain ids include: " "1 (mainnet), 3 (ropsten), 4 (rinkeby), 5 (goerli) and 42 (kovan). " "Please try again with a valid registry URI.")
def validate_empty_bytes(offset: int, length: int, bytecode: bytes) -> None: """ Validates that segment [`offset`:`offset`+`length`] of `bytecode` is comprised of empty bytes (b'\00'). """ slot_length = offset + length slot = bytecode[offset:slot_length] if slot != bytearray(length): raise ValidationError( f"Bytecode segment: [{offset}:{slot_length}] is not comprised of empty bytes, " f"rather: {slot}.")
def validate_manifest_against_schema(manifest: Dict[str, Any]) -> None: """ Load and validate manifest against schema located at MANIFEST_SCHEMA_PATH. """ schema_data = _load_schema_data() try: validate(manifest, schema_data) except jsonValidationError: raise ValidationError("Manifest:{0} invalid for schema:{1}".format( manifest, MANIFEST_SCHEMA_PATH))
def validate_meta_object(meta: Dict[str, Any], allow_extra_meta_fields: bool) -> None: """ Validates that every key is one of `META_FIELDS` and has a value of the expected type. """ for key, value in meta.items(): if key in META_FIELDS: if type(value) is not META_FIELDS[key]: raise ValidationError( f"Values for {key} are expected to have the type {META_FIELDS[key]}, " f"instead got {type(value)}.") elif allow_extra_meta_fields: if key[:2] != "x-": raise ValidationError( "Undefined meta fields need to begin with 'x-', " f"{key} is not a valid undefined meta field.") else: raise ValidationError( f"{key} is not a permitted meta field. To allow undefined fields, " "set `allow_extra_meta_fields` to True.")
def validate_manifest_against_schema(manifest: Dict[str, Any]) -> None: """ Load and validate manifest against schema located at MANIFEST_SCHEMA_PATH. """ schema_data = _load_schema_data() try: validate(manifest, schema_data) except jsonValidationError as e: raise ValidationError( f"Manifest invalid for schema version {schema_data['version']}. " f"Reason: {e.message}")
def validate_minimal_contract_data_present(contract_data): """ Validate that contract data contains at least one of the following keys necessary to generate contract factory. "abi", "bytecode", "runtime_bytecode" """ if not any(key in contract_data.keys() for key in ("abi", "bytecode", "runtime_bytecode")): raise ValidationError( "Minimum required contract data (abi/bytecode/runtime_bytecode) not found." )
def validate_uri_contents(contents: bytes, validation_hash: str) -> None: """ Validate that the keccak(contents) matches the validation_hash. """ hashed_contents = keccak(contents) decoded_validation = decode_hex(validation_hash) if hashed_contents != decoded_validation: raise ValidationError( "Invalid content-addressed URI. " f"Validation hash:{to_hex(decoded_validation)} does not match the " f"hash of URI contents: {to_hex(hashed_contents)}." )
def _validate_name_and_references(self, name: str) -> None: validate_contract_name(name) if name not in self.deployment_data: raise KeyError( "Contract name not found in deployment data. " f"Available deployments include: {list(sorted(self.deployment_data.keys()))}." ) contract_type = self.deployment_data[name]["contract_type"] if contract_type not in self.contract_factories: raise ValidationError( f"Contract type: {contract_type} for alias: {name} not found. " f"Available contract types include: {list(sorted(self.contract_factories.keys()))}." )
def validate_manifest_deployments(manifest: Dict[str, Any]) -> None: """ Validate that a manifest's deployments contracts reference existing contract_types. """ if set(("contract_types", "deployments")).issubset(manifest): all_contract_types = list(manifest["contract_types"].keys()) all_deployments = list(manifest["deployments"].values()) all_deployment_names = extract_contract_types_from_deployments(all_deployments) missing_contract_types = set(all_deployment_names).difference( all_contract_types ) if missing_contract_types: raise ValidationError( f"Manifest missing references to contracts: {missing_contract_types}." )
def validate_blob_uri_contents(contents: bytes, blob_uri: str) -> None: """ Raises an exception if the sha1 hash of the contents does not match the hash found in te blob_uri. Formula for how git calculates the hash found here: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html """ blob_path = parse.urlparse(blob_uri).path blob_hash = blob_path.split("/")[-1] contents_str = to_text(contents) content_length = len(contents_str) hashable_contents = "blob " + str(content_length) + "\0" + contents_str hash_object = hashlib.sha1(to_bytes(text=hashable_contents)) if hash_object.hexdigest() != blob_hash: raise ValidationError( f"Hash of contents fetched from {blob_uri} do not match its hash: {blob_hash}." )
def validate_package_deployments(package_data: Dict[str, Any]) -> None: """ Validate that a package's deployments contracts reference existing contract_types. """ if set(("contract_types", "deployments")).issubset(package_data): all_contract_types = list(package_data["contract_types"].keys()) all_deployments = list(package_data["deployments"].values()) all_deployment_names = set( itertools.chain.from_iterable(deployment for deployment in all_deployments)) missing_contract_types = set(all_deployment_names).difference( all_contract_types) if missing_contract_types: raise ValidationError( "Package missing references to contracts: {0}.".format( missing_contract_types))
def validate_linked_references(link_deps: Tuple[Tuple[int, bytes], ...], bytecode: bytes) -> None: """ Validates that normalized linked_references (offset, expected_bytes) match the corresponding bytecode. """ offsets, values = zip(*link_deps) for idx, offset in enumerate(offsets): value = values[idx] # https://github.com/python/mypy/issues/4975 offset_value = int(offset) # type: ignore dep_length = len(value) # type: ignore end_of_bytes = offset_value + dep_length # Ignore b/c whitespace around ':' conflict b/w black & flake8 actual_bytes = bytecode[offset_value:end_of_bytes] # noqa: E203 if actual_bytes != values[idx]: raise ValidationError("Error validating linked reference. " f"Offset: {offset} " f"Value: {values[idx]} " f"Bytecode: {bytecode} .")
def validate_registry_uri(uri: str) -> None: """ Raise an exception if the URI does not conform to the registry URI scheme. """ parsed = parse.urlparse(uri) scheme, authority, pkg_path, version = ( parsed.scheme, parsed.netloc, parsed.path, parsed.query, ) validate_registry_uri_scheme(scheme) validate_registry_uri_authority(authority) pkg_name = pkg_path.lstrip("/") if pkg_name: validate_package_name(pkg_name) if not pkg_name and version: raise ValidationError( "Registry URIs cannot provide a version without a package name.") if version: validate_registry_uri_version(version)
def get_contract_type(self, name: str, w3: Web3 = None) -> Contract: """ API to generate a contract factory class. """ current_w3 = None if w3 is not None: current_w3 = w3 else: current_w3 = self.w3 validate_contract_name(name) validate_w3_instance(current_w3) if name in self.package_data['contract_types']: contract_data = self.package_data['contract_types'][name] validate_minimal_contract_data_present(contract_data) contract_kwargs = generate_contract_factory_kwargs(contract_data) contract_factory = current_w3.eth.contract(**contract_kwargs) return contract_factory raise ValidationError( "Package does not have contract by name: {}.".format(name))
def validate_raw_manifest_format(raw_manifest: str) -> None: """ Raise a ValidationError if a manifest ... - is not tightly packed (i.e. no linebreaks or extra whitespace) - does not have alphabetically sorted keys - has duplicate keys - is not UTF-8 encoded - has a trailing newline """ try: manifest_dict = json.loads(raw_manifest, encoding="UTF-8") except json.JSONDecodeError as err: raise json.JSONDecodeError( "Failed to load package data. File is not a valid JSON document.", err.doc, err.pos, ) compact_manifest = json.dumps(manifest_dict, sort_keys=True, separators=(",", ":")) if raw_manifest != compact_manifest: raise ValidationError( "The manifest appears to be malformed. Please ensure that it conforms to the " "EthPM-Spec for document format. " "http://ethpm.github.io/ethpm-spec/package-spec.html#document-format " )
def validate_ipfs_uri(uri: str) -> None: """ Raise an exception if the provided URI is not a valid IPFS URI. """ if not is_ipfs_uri(uri): raise ValidationError(f"URI: {uri} is not a valid IPFS URI.")
def validate_deployments_are_present(manifest: Dict[str, Any]) -> None: if "deployments" not in manifest: raise ValidationError("Manifest doesn't have a deployments key.") if not manifest["deployments"]: raise ValidationError("Manifest's deployments key is empty.")
def validate_registry_uri_scheme(scheme: str) -> None: """ Raise an exception if the scheme is not the valid registry URI scheme ('ercXXX'). """ if scheme != REGISTRY_URI_SCHEME: raise ValidationError(f"{scheme} is not a valid registry URI scheme.")
def validate_build_dependencies_are_present(manifest: Dict[str, Any]) -> None: if "build_dependencies" not in manifest: raise ValidationError("Manifest doesn't have any build dependencies.") if not manifest["build_dependencies"]: raise ValidationError("Manifest's build dependencies key is empty.")
def validate_deployments_are_present(package_data: Dict[str, Any]) -> None: if "deployments" not in package_data: raise ValidationError("Package doesn't have a deployments key.") if not package_data["deployments"]: raise ValidationError("Package's deployments key is empty.")
def validate_contract_name(name): if not CONTRACT_NAME_REGEX.match(name): raise ValidationError("Contract name: {0} is not valid.".format(name))
def validate_contract_name(name: str) -> None: if not CONTRACT_NAME_REGEX.match(name): raise ValidationError(f"Contract name: {name} is not valid.")