def parse_query_parameters(params: Dict[str, str]) -> Dict[str, Any]: query_params: Dict[str, Any] = {} if not params.get("q"): raise exceptions.ValidationException( "User must specify a redisearch query string.") query_params["q"] = params["q"] if params.get("transaction_type"): query_params["transaction_type"] = params["transaction_type"] query_params["id_only"] = params.get( "id_only") and params["id_only"].lower() != "false" or False query_params["verbatim"] = params.get( "verbatim") and params["verbatim"].lower() != "false" or False if params.get("sort_by"): query_params["sort_by"] = params["sort_by"] query_params["sort_asc"] = params.get( "sort_asc") and params["sort_asc"].lower() != "false" if query_params[ "sort_asc"] is None: # the above line resolves to None if the get fails query_params["sort_asc"] = True try: query_params["limit"] = int( params["limit"]) if params.get("limit") else 10 query_params["offset"] = int( params["offset"]) if params.get("offset") else 0 except ValueError: raise exceptions.ValidationException( "Limit and offset must be integer values.") return query_params
def public_blockchain_transaction_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json if not data.get("network"): raise exceptions.ValidationException("Invalid parameter: network") try: if data["network"] in ["BTC_MAINNET", "BTC_TESTNET3"]: _validate_bitcoin_transaction_v1(data.get("transaction")) elif data["network"] in [ "ETH_MAINNET", "ETH_ROPSTEN", "ETC_MAINNET", "ETC_MORDEN" ]: _validate_ethereum_transaction_v1(data.get("transaction")) else: raise exceptions.ValidationException( "User input did not match JSON schema") except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException( "User input did not match JSON schema") return helpers.flask_http_response( 200, interchain.legacy_sign_blockchain_transaction_v1( data["network"], data["transaction"]))
def validate_schedule(self) -> None: if self.cron and self.seconds: raise exceptions.ValidationException("can only have one of 'seconds' or 'cron'") if self.cron: try: CronTrigger.from_crontab(self.cron) except ValueError: raise exceptions.ValidationException("The provided cron string is invalid")
def update_api_key_v1(key_id: str) -> Tuple[str, int, Dict[str, str]]: if not key_id: raise exceptions.ValidationException("Invalid parameter: key_id") if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") body = flask.request.json try: _validate_api_key_update_v1(body) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) api_keys.update_api_key_v1(key_id, body["nickname"]) return helpers.flask_http_response(200, helpers.format_success(True))
def process_receipt_v1(block_dto: Dict[str, Any]) -> None: if not block_dto: raise exceptions.ValidationException("block_dto missing") _log.info( f"[RECEIPT] Got receipt from L{block_dto['header']['level']}: {block_dto}" ) block_model = cast("model.BlockModel", None) # This will always get defined, or it will raise level_received_from: int = block_dto["header"]["level"] if level_received_from == 2: block_model = l2_block_model.new_from_at_rest(block_dto) elif level_received_from == 3: block_model = l3_block_model.new_from_at_rest(block_dto) elif level_received_from == 4: block_model = l4_block_model.new_from_at_rest(block_dto) elif level_received_from == 5: block_model = l5_block_model.new_from_at_rest(block_dto) else: raise exceptions.InvalidNodeLevel("Unsupported level receipt") _log.info(f"Block model {block_model.__dict__}") l1_block_id_set = block_model.get_associated_l1_block_id() _log.info( f"Processing receipt for blocks {l1_block_id_set} from L{level_received_from}" ) for l1_block_id in l1_block_id_set: # Check that the chain which sent this receipt is in our claims, and that this L1 block is accepting receipts for this level validations = matchmaking.get_claim_check( l1_block_id)["validations"][f"l{level_received_from}"] if ( block_model.dc_id in validations ) and broadcast_functions.is_block_accepting_verifications_from_level( l1_block_id, level_received_from): _log.info( f"Verified that block {l1_block_id} was sent. Inserting receipt" ) storage_location = broadcast_functions.verification_storage_location( l1_block_id, level_received_from, block_model.dc_id) storage.put_object_as_json(storage_location, block_model.export_as_at_rest()) # Set new receipt for matchmaking claim check try: block_id = block_model.block_id proof = block_model.proof dc_id = block_model.dc_id matchmaking.add_receipt(l1_block_id, level_received_from, dc_id, block_id, proof) except Exception: _log.exception("matchmaking add_receipt failed!") # Update the broadcast system about this receipt broadcast_functions.set_receieved_verification_for_block_from_chain_sync( l1_block_id, level_received_from, block_model.dc_id) else: _log.warning( f"Chain {block_model.dc_id} (level {level_received_from}) returned a receipt that wasn't expected (possibly expired?) for block {l1_block_id}. Rejecting receipt" # noqa: B950 ) raise exceptions.NotAcceptingVerifications( f"Not accepting verifications for block {l1_block_id} from {block_model.dc_id}" )
def delete_transaction_type_v1(txn_type: str, **kwargs) -> Tuple[str, int, Dict[str, str]]: if not txn_type: raise exceptions.ValidationException("Invalid parameter: txn_type") transaction_types.delete_transaction_type_v1(txn_type) return helpers.flask_http_response(200, helpers.format_success(True))
def get_transaction_type_v1(txn_type: str, **kwargs) -> Tuple[str, int, Dict[str, str]]: if not txn_type: raise exceptions.ValidationException("Invalid parameter: txn_type") return helpers.flask_http_response( 200, transaction_types.get_transaction_type_v1(txn_type))
def delete_api_key_v1(key_id: str, **kwargs) -> Tuple[str, int, Dict[str, str]]: if not key_id: raise exceptions.ValidationException("Invalid parameter: key_id") api_keys.delete_api_key_v1(key_id=key_id) return helpers.flask_http_response(200, helpers.format_success(True))
def update_transaction_type_v1(txn_type: str) -> Tuple[str, int, Dict[str, str]]: if not txn_type: raise exceptions.ValidationException("Invalid parameter: txn_type") if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") content = flask.request.json try: _validate_update_txn_type_v1(content) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException("User input did not match JSON schema") transaction_types.update_transaction_type_v1(txn_type, content["custom_indexes"]) return helpers.flask_http_response(200, helpers.format_success(True))
def query_transaction_v1() -> Tuple[str, int, Dict[str, str]]: params = helpers.parse_query_parameters(flask.request.args.to_dict()) if params.get("transaction_type"): should_parse = flask.request.headers.get("Parse-Payload") != "false" return helpers.flask_http_response( 200, transactions.query_transactions_v1(params, should_parse)) raise exceptions.ValidationException( "User input must specify transaction type to query")
def validate_secret_names(self) -> None: if self.secrets is None: return regex = "[a-zA-Z][a-zA-Z0-9-]{0,16}" pattern = re.compile(regex) for secret in self.secrets: if not pattern.fullmatch(secret): raise exceptions.ValidationException(f"secret names must match regex {regex}")
def update_api_key_v1(key_id: str, **kwargs) -> Tuple[str, int, Dict[str, str]]: if not key_id: raise exceptions.ValidationException("Invalid parameter: key_id") if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") body = flask.request.json try: _validate_api_key_update_v1(body) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 200, api_keys.update_api_key_v1(key_id, body.get("nickname"), body.get("permissions_document")))
def check_env_names(self) -> None: if self.env is None: return for key in self.env: self.env[key] = str(self.env[key]) regex = "[a-zA-Z][a-zA-Z0-9._-]+" pattern = re.compile(regex) for env_var in self.env: if not pattern.fullmatch(env_var): raise exceptions.ValidationException(f"env names must match regex {regex}")
def update_bitcoin_interchain_v1(name: str) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_bitcoin_network_update_v1(data) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 200, interchain.update_bitcoin_interchain_v1(name, data))
def create_binance_interchain_v1(**kwargs) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_binance_network_create_v1(data) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 201, interchain.create_binance_interchain_v1(data))
def verify_custom_indexes_options(custom_indexes: Iterable["custom_index"]) -> None: """Validate an array of custom index DTOs from user input (Raises on error)""" for index in custom_indexes: index_type = index.get("type") if index_type == "text": _valid_custom_text_index_options_v1(index.get("options") or {}) elif index_type == "tag": _valid_custom_tag_index_options_v1(index.get("options") or {}) elif index_type == "number": _valid_custom_number_index_options_v1(index.get("options") or {}) else: raise exceptions.ValidationException(f"Index {index} does not contain a valid type")
def create_api_key_v1() -> Tuple[str, int, Dict[str, str]]: nickname = "" if flask.request.is_json: body = flask.request.json try: _validate_api_key_creation_v1(body) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) nickname = body.get("nickname") or "" return helpers.flask_http_response(201, api_keys.create_api_key_v1(nickname))
def create_ethereum_interchain_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_ethereum_network_create_v1(data) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException( "User input did not match JSON schema") return helpers.flask_http_response( 201, interchain.create_ethereum_interchain_v1(data))
def create_binance_transaction_v1(name: str, **kwargs) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_binance_transaction_v1(data) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 200, interchain.sign_interchain_transaction_v1("binance", name, data))
def set_default_network_v1(**kwargs) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_set_default_interchain_v1(data) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 200, interchain.set_default_interchain_v1(data["blockchain"], data["name"]))
def update_contract_v1(contract_id: str) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") update = flask.request.json try: _validate_sc_update_v1(update) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException("User input did not match JSON schema") return helpers.flask_http_response(202, smart_contracts.update_contract_v1(contract_id, update))
def register_transaction_type_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") content = flask.request.json try: _validate_create_txn_type_v1(content) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException("User input did not match JSON schema") transaction_types.register_transaction_type_v1(content) return helpers.flask_http_response(200, helpers.format_success(True))
def create_bitcoin_transaction_v1( name: str) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") data = flask.request.json try: _validate_bitcoin_transaction_v1(data) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException( "User input did not match JSON schema") return helpers.flask_http_response( 200, interchain.sign_interchain_transaction_v1("bitcoin", name, data))
def post_transaction_v1(**kwargs) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") txn = flask.request.json try: _validate_txn_create_v1(txn) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) return helpers.flask_http_response( 201, transactions.submit_transaction_v1(txn, flask.request.headers.get("X-Callback-URL"), api_key=kwargs["used_auth_key"]) )
def post_contract_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") contract = flask.request.json try: _validate_sc_create_v1(contract) if contract.get("custom_indexes"): helpers.verify_custom_indexes_options(contract.get("custom_indexes")) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException("User input did not match JSON schema") return helpers.flask_http_response(202, smart_contracts.create_contract_v1(contract))
def enqueue_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") content = flask.request.json deadline = int(cast(str, flask.request.headers.get( "deadline"))) if flask.request.headers.get("deadline") else 30 try: _validate_broadcast_schema_v1(content) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) dragonnet.enqueue_item_for_verification_v1(content, deadline) return helpers.flask_http_response(200, helpers.format_success(True))
def register_transaction_type_v1(**kwargs) -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") content = flask.request.json try: _validate_create_txn_type_v1(content) if content.get("custom_indexes"): helpers.verify_custom_indexes_options(content["custom_indexes"]) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) transaction_types.register_transaction_type_v1(content) return helpers.flask_http_response(200, helpers.format_success(True))
def query_transactions_v1(params: Dict[str, Any], parse: bool = True) -> "RSearch": """invoke queries on redisearch indexes Args: params: Dictionary of redisearch query options parse: If true, parse the transaction payload before returning Returns: {"results": [], "total": total} storage objects matching search query """ if not params.get("transaction_type"): raise exceptions.ValidationException( "transaction_type must be supplied for transaction queries") try: query_result = redisearch.search( index=params["transaction_type"], query_str=params["q"], only_id=params.get("id_only"), verbatim=params.get("verbatim"), offset=params.get("offset"), limit=params.get("limit"), sort_by=params.get("sort_by"), sort_asc=params.get("sort_asc"), ) except redis.exceptions.ResponseError as e: error_str = str(e) # Detect if this is a syntax error; if so, throw it back as a 400 with the message if error_str.startswith("Syntax error"): raise exceptions.BadRequest(error_str) # If unknown index, user provided a bad transaction type elif error_str == "Unknown Index name": raise exceptions.BadRequest("Invalid transaction type") else: raise result: "RSearch" = {"total": query_result.total, "results": []} if params.get("id_only"): result["results"] = [x.id for x in query_result.docs] else: transactions = [] for doc in query_result.docs: block_id = doc.block_id transaction_id = doc.id retrieved_txn = storage.select_transaction(block_id, transaction_id) if parse: retrieved_txn["payload"] = json.loads(retrieved_txn["payload"]) transactions.append(retrieved_txn) result["results"] = transactions return result
def dragonnet_auth_v1() -> Tuple[str, int, Dict[str, str]]: """ Create a new DragonNet interchain communication key pair with the requester (unauthenticated by design) """ if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") body = flask.request.json try: _validate_interchain_auth_v1(body) except fastjsonschema.JsonSchemaException as e: raise exceptions.ValidationException(str(e)) dragonnet.register_interchain_auth_v1(body) return helpers.flask_http_response(201, helpers.format_success(True))
def post_transaction_v1() -> Tuple[str, int, Dict[str, str]]: if not flask.request.is_json: raise exceptions.BadRequest("Could not parse JSON") txn = flask.request.json try: _validate_txn_create_v1(txn) except fastjsonschema.JsonSchemaException: raise exceptions.ValidationException( "User input did not match JSON schema") return helpers.flask_http_response( 201, transactions.submit_transaction_v1( txn, flask.request.headers.get("X-Callback-URL")))