def convert_int_to_hex_str(value: int): try: if is_integer(value): return add_0x_prefix(hex(value)) else: raise DataTypeException("Data's type should be integer.") except KeyError: raise DataTypeException("Data type is wrong.")
def convert_bytes_to_hex_str(value: bytes): try: if is_bytes(value): return add_0x_prefix(value.hex()) else: raise DataTypeException("Data's type should be bytes.") except KeyError: raise DataTypeException("Data type is wrong.")
def is_T_HASH(value): """T_HASH is data type which is 64-digit hexadecimal string prefixed with `0x`.""" try: if is_0x_prefixed(value) and len(remove_0x_prefix(value)) == 64: return True else: raise DataTypeException("This hash value is unrecognized.") except ValueError: raise DataTypeException("This hash value is unrecognized.")
def is_T_BIN_DATA(value): """ T_BIN_DATA is data type which is hexadeciamal string prefixed with `0x` and length is even. """ try: if is_0x_prefixed(value) and len(remove_0x_prefix(value)) % 2 == 0: return True else: raise DataTypeException("This value is not T_BIN_DATA data type.") except ValueError: raise DataTypeException("This value is not T_BIN_DATA data type.")
def build(self) -> Transaction: if not self._to or not self._step_limit: raise DataTypeException( "'to' and 'step_limit' should be required.") return Transaction(self._from_, self._to, self._value, self._step_limit, self._nid, self._nonce, self._version, self._timestamp)
def build(self) -> CallTransaction: if not self._method: raise DataTypeException("'method' should be required.") return CallTransaction(self._from_, self._to, self._value, self._step_limit, self._nid, self._nonce, self._version, self._timestamp, self._method, self._params)
def call(self, call: object): """ Calls SCORE's external function which is read-only without creating a transaction on Loopchain. Delegates to icx_call RPC method. :param call: Call object made by CallBuilder :return: Values returned by the executed SCORE function """ if not isinstance(call, Call): raise DataTypeException("Call object is unrecognized.") params = { "to": call.to, "dataType": "call", "data": { "method": call.method } } if call.from_ is not None: params["from"] = call.from_ if isinstance(call.params, dict): params["data"]["params"] = call.params return self.__provider.make_request('icx_call', params)
def get_block(self, value): """ If param is height, 1. Returns block information by block height 2. Delegates to icx_getBlockByHeight RPC method Or block hash, 1. Returns block information by block hash 2. Delegates to icx_getBlockByHash RPC method Or string value same as `latest`, 1. Returns the last block information 2. Delegates to icx_getLastBlock RPC method :param value: Integer of a block height or hash of a block prefixed with '0x' or `latest` :return result: Block data """ # by height if is_block_height(value): params = {'height': add_0x_prefix(hex(value))} result = self.__provider.make_request('icx_getBlockByHeight', params) # by hash elif is_hex_block_hash(value): params = {'hash': value} result = self.__provider.make_request('icx_getBlockByHash', params) # by value elif is_predefined_block_value(value): result = self.__provider.make_request('icx_getLastBlock') else: raise DataTypeException("It's unrecognized block reference:{0!r}.".format(value)) return result
def estimate_step(self, transaction: Transaction, full_response: bool = False) -> int: """ Returns an estimated step of how much step is necessary to allow the transaction to complete. :param transaction: a raw transaction :param full_response: a boolean indicating whether or not it returns refined data :return: an estimated step """ if not isinstance(transaction, Transaction): raise DataTypeException("Transaction object is unrecognized.") params = { "version": convert_int_to_hex_str(transaction.version) if transaction.version else "0x3", "from": transaction.from_, "to": transaction.to, "timestamp": convert_int_to_hex_str(transaction.timestamp) if transaction.timestamp else get_timestamp(), "nid": convert_int_to_hex_str(transaction.nid) if transaction.nid else "0x1" } if transaction.value is not None: params["value"] = convert_int_to_hex_str(transaction.value) if transaction.nonce is not None: params["nonce"] = convert_int_to_hex_str(transaction.nonce) if transaction.data_type is not None: params["dataType"] = transaction.data_type if transaction.data_type in ('deploy', 'call'): params["data"] = generate_data_value(transaction) elif transaction.data_type == 'message': params["data"] = transaction.data result = self.__provider.make_request('debug_estimateStep', params, full_response) return result if full_response else int(result, 16)
def call(self, call: object, full_response: bool = False) -> Union[dict, str]: """ Calls SCORE's external function which is read-only without creating a transaction. Delegates to icx_call RPC method. :param call: Call object made by CallBuilder :param full_response: Boolean to check whether get naive dict or refined data from server :return: Values returned by the executed SCORE function """ if not isinstance(call, Call): raise DataTypeException("Call object is unrecognized.") params = { "to": call.to, "dataType": "call", "data": { "method": call.method } } if call.from_ is not None: params["from"] = call.from_ if isinstance(call.params, dict): params["data"]["params"] = call.params return self.__provider.make_request('icx_call', params, full_response)
def build(self) -> DeployTransaction: if not self._content_type or not self._content: raise DataTypeException( "'content_type' and 'content' should be required.") return DeployTransaction(self._from_, self._to, None, self._step_limit, self._nid, self._nonce, self._version, self._timestamp, self._content_type, self._content, self._params)
def from_dict(cls, transaction_as_dict: dict) -> 'MessageTransactionBuilder': """Returns a MessageTransactionBuilder made from dict""" try: cls = super().from_dict(transaction_as_dict) cls.data(transaction_as_dict["data"]) return cls except KeyError: raise DataTypeException("The input data invalid. Mapping key not found.")
def __init__(self, from_: str, to: str, value: int, step_limit: int, nid: int, nonce: int, version: int, timestamp: int, data: str): Transaction.__init__(self, from_, to, value, step_limit, nid, nonce, version, timestamp) if is_0x_prefixed(data) and is_lowercase_hex_string(remove_0x_prefix(data)): self.__data = data else: raise DataTypeException("Message data should be hex string prefixed with '0x'.")
def from_dict(cls, transaction_as_dict: dict) -> 'CallTransactionBuilder': """Returns a CallTransactionBuilder made from dict""" try: cls = super().from_dict(transaction_as_dict) cls.method(transaction_as_dict["method"]) cls.params(transaction_as_dict["params"] if "params" in transaction_as_dict else None) return cls except KeyError: raise DataTypeException("The input data invalid. Mapping key not found.")
def from_dict(cls, transaction_as_dict: dict) -> 'DeployTransactionBuilder': """Returns a DeployTransactionBuilder made from dict""" try: cls = super().from_dict(transaction_as_dict) cls.content(transaction_as_dict['content']) cls.content_type(transaction_as_dict['content_type']) cls.params(transaction_as_dict['params'] if "params" in transaction_as_dict else None) return cls except KeyError: raise DataTypeException("The input data invalid. Mapping key not found.")
def build(self) -> DepositTransaction: if not self._action: raise DataTypeException( "'action' should be provided. Available values are 'add' or 'withdraw'." ) if self._action == "withdraw": if not self._id: raise DataTypeException( "When action is 'withdraw', 'id' should be provided.") if self._value: raise DataTypeException( "When action is 'withdraw'. 'value' should not be provided." ) if self._action == "add" and not self._value: raise DataTypeException( "When action is 'add', 'value' should be provided.") return DepositTransaction(self._from_, self._to, self._value, self._step_limit, self._nid, self._nonce, self._version, self._timestamp, self._action, self._id)
def __init__(self, from_: str, to: str, value: int, step_limit: int, nid: int, nonce: int, version: int, timestamp: int, content_type: str, content: bytes, params: dict): Transaction.__init__(self, from_, to, value, step_limit, nid, nonce, version, timestamp) self.__content_type = content_type # Content should not be empty. if not content: raise DataTypeException("Content type should be bytes.") self.__content = content self.__params = params
def from_dict(cls, call_as_dict: dict) -> 'CallBuilder': """Returns a CallBuilder made from dict""" try: return cls(from_=call_as_dict['from_'], to=call_as_dict['to'], method=call_as_dict['method'], params=call_as_dict['params'] if "params" in call_as_dict else None) except KeyError: raise DataTypeException( "The input data invalid. Mapping key not found.")
def load(private_key: bytes): """Loads a wallet from a private key and generates an instance of Wallet. :param private_key: private key in bytes :return: An instance of Wallet class. """ try: private_key_object = PrivateKey(private_key) wallet = KeyWallet(private_key_object) return wallet except TypeError: raise DataTypeException("Private key is invalid.")
def convert_params_value_to_hex_str(params: dict) -> dict: """Converts params' values into hex str prefixed with '0x'.""" if isinstance(params, dict): new_params = params for key, value in params.items(): if isinstance(value, int): new_params[key] = convert_int_to_hex_str(value) elif isinstance(value, bytes): new_params[key] = convert_bytes_to_hex_str(value) return new_params else: raise DataTypeException("Params type should be dict.")
def from_dict(cls, transaction_as_dict: dict) -> 'DepositTransactionBuilder': """Returns a DepositTransactionBuilder made from dict""" try: cls = super().from_dict(transaction_as_dict) cls.action(transaction_as_dict["action"]) cls.id(transaction_as_dict["id"] if "id" in transaction_as_dict else None) return cls except KeyError: raise DataTypeException( "The input data invalid. Mapping key not found.")
def get_transaction(self, tx_hash: str): """ Returns the transaction information requested by transaction hash. Delegates to icx_getTransactionByHash RPC method. :param tx_hash: Transaction hash prefixed with '0x' :return: Information about a transaction """ if is_T_HASH(tx_hash): params = {'txHash': tx_hash} return self.__provider.make_request('icx_getTransactionByHash', params) else: raise DataTypeException("This hash value is unrecognized.")
def get_transaction_result(self, tx_hash: str): """ Returns the transaction result requested by transaction hash. Delegates to icx_getTransactionResult RPC method. :param tx_hash: Hash of a transaction prefixed with '0x' :return A transaction result object """ if is_T_HASH(tx_hash): params = {'txHash': tx_hash} return self.__provider.make_request('icx_getTransactionResult', params) else: raise DataTypeException("This hash value is unrecognized.")
def is_lowercase_hex_string(value: str) -> bool: """Check whether value is hexadecimal format or not :param value: text :return: True(lowercase hexadecimal) otherwise False """ try: result = None if isinstance(value, str): result = match('[0-9a-f]+', value) return result is not None and len(result.group(0)) == len(value) except Exception: raise DataTypeException("Not lowercase hex string. Get: {0}.".format( repr(value)))
def get_trace(self, tx_hash: str) -> dict: """ Get trace of the transaction :param tx_hash: Transaction hash prefixed with '0x' :return: trace """ if not is_T_HASH(tx_hash): raise DataTypeException("This hash value is unrecognized.") params = {'txHash': tx_hash} result = self.__provider.make_request('debug_getTrace', params) return result
def from_dict(cls, transaction_as_dict: dict) -> 'TransactionBuilder': """Returns a TransactionBuilder made from dict""" try: return cls( from_=transaction_as_dict['from_'] if "from_" in transaction_as_dict else None, to=transaction_as_dict['to'], value=transaction_as_dict['value'] if "value" in transaction_as_dict else None, step_limit=transaction_as_dict['step_limit'] if "step_limit" in transaction_as_dict else None, nid=transaction_as_dict['nid'] if 'nid' in transaction_as_dict else None, nonce=transaction_as_dict["nonce"] if "nonce" in transaction_as_dict else None, version=transaction_as_dict["version"] if "version" in transaction_as_dict else None, timestamp=transaction_as_dict["timestamp"] if "timestamp" in transaction_as_dict else None ) except KeyError: raise DataTypeException("The input data invalid. Mapping key not found.")
def load(private_key: bytes) -> 'KeyWallet': """Loads a wallet from a private key and generates an instance of Wallet. :param private_key: private key in bytes :return: An instance of Wallet class. """ try: private_key_object = PrivateKey(private_key) wallet = KeyWallet(private_key_object) logger.info( f"Loaded Wallet by the private key. Address: {wallet.get_address()}" ) return wallet except TypeError: raise DataTypeException("Private key is invalid.")
def get_block(self, value: Union[int, str], full_response: bool = False) -> dict: """ If param is height, 1. Returns block information by block height 2. Delegates to icx_getBlockByHeight RPC method Or block hash, 1. Returns block information by block hash 2. Delegates to icx_getBlockByHash RPC method Or string value same as `latest`, 1. Returns the last block information 2. Delegates to icx_getLastBlock RPC method :param value: Integer of a block height or hash of a block prefixed with '0x' or `latest` :param full_response: Boolean to check whether get naive dict or refined data from server :return result: Block data """ # by height if is_block_height(value): params = {'height': add_0x_prefix(hex(value))} result = self.__provider.make_request('icx_getBlockByHeight', params, full_response) # by hash elif is_hex_block_hash(value): params = {'hash': value} result = self.__provider.make_request('icx_getBlockByHash', params, full_response) # by value elif is_predefined_block_value(value): result = self.__provider.make_request('icx_getLastBlock', full_response=full_response) else: raise DataTypeException( "It's unrecognized block reference:{0!r}.".format(value)) if not full_response: convert_block(result) return result
def get_transaction(self, tx_hash: str, full_response: bool = False) -> dict: """ Returns the transaction information requested by transaction hash. Delegates to icx_getTransactionByHash RPC method. :param tx_hash: Transaction hash prefixed with '0x' :param full_response: Boolean to check whether get naive dict or refined data from server :return: Information about a transaction """ if not is_T_HASH(tx_hash): raise DataTypeException("This hash value is unrecognized.") params = {'txHash': tx_hash} result = self.__provider.make_request('icx_getTransactionByHash', params, full_response) if not full_response: result = convert(result, TRANSACTION) return result
def wait_transaction_result(self, tx_hash: str, full_response: bool = False) -> dict: """ Returns the result of a transaction specified by the transaction hash like get_transaction_result, but waits for some time to get the transaction result instead of returning immediately if there is no finalized result. Delegates to icx_WaitTransactionResult RPC method. :param tx_hash: Hash of a transaction prefixed with '0x' :param full_response: Boolean to check whether get naive dict or refined data from server :return A transaction result object """ if not is_T_HASH(tx_hash): raise DataTypeException("This hash value is unrecognized.") params = {'txHash': tx_hash} result = self.__provider.make_request('icx_waitTransactionResult', params, full_response) if not full_response: result = convert(result, TRANSACTION_RESULT) return result