def get_network_type(cls): """Returns the WAZN network type the faucet is running on. :returns: network type (stagenet, testnet) :raises RpcConnectionError: no connection could be established :raises ValueError: retrieved data could not be processed """ if not cls.network_type: rpc_connection = AuthServiceProxy("http://{0}:{1}/json_rpc".format( settings.DAEMON_HOST, settings.DAEMON_PORT)) result = None try: result = rpc_connection.get_info() except ( requests.HTTPError, requests.ConnectionError, JSONRPCException, ) as e: logger.error("RPC Error on getting address" + str(e)) logger.exception(e) raise RpcConnectionError(str(e)) # Check network type network_type = result.get("nettype", None) if not network_type: raise ValueError("Error with: {0}".format(result)) cls.network_type = network_type return cls.network_type
def test_rpc_error_raises_error(self): responses.add( responses.POST, self.dummy_url, status=200, json={"error": "dummy error"}, ) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.dummy_method()
def get_address(): """Returns the current wallet's address. :returns: wallet's address if successful :raises RpcConnectionError: no connection could be established :raises ValueError: retrieved data could not be processed """ # get the wallet's address rpc_connection = AuthServiceProxy("http://{0}:{1}/json_rpc".format( settings.WALLET_HOST, settings.WALLET_PORT)) result = None try: result = rpc_connection.get_address() except ( requests.HTTPError, requests.ConnectionError, JSONRPCException, ) as e: logger.error("RPC Error on getting address" + str(e)) logger.exception(e) raise RpcConnectionError(str(e)) address = result.get("address", None) # check address if not address: raise ValueError("Eror with: {0}".format(result)) return address
def get_balance(): """Returns the current balance of the wallet. :returns: unlocked_balance if successful in WAZN format :raises RpcConnectionError: no connection could be established :raises ValueError: retrieved data could not be processed """ # get the current balance rpc_connection = AuthServiceProxy("http://{0}:{1}/json_rpc".format( settings.WALLET_HOST, settings.WALLET_PORT)) result = None try: result = rpc_connection.getbalance() except ( requests.HTTPError, requests.ConnectionError, JSONRPCException, ) as e: logger.error("RPC Error on getting balance" + str(e)) raise RpcConnectionError(str(e)) balance = result.get("unlocked_balance", None) # check unlocked_balance key # balance can be 0, therefore check for None if balance is None: raise ValueError("Error with: {0}".format(result)) return balance
def test_other_request_error(self): """Mock other errors connecting to server. """ responses.add(responses.POST, self.dummy_url, body=RequestException("")) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.get_balance()
def test_timeout_error(self): """Mock timeout connecting to server. """ responses.add(responses.POST, self.dummy_url, body=Timeout("")) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.get_balance()
def test_connection_error(self): """Mock no connection to server error. """ responses.add(responses.POST, self.dummy_url, body=ConnectionError("")) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.get_balance()
def test_jsondecode_request_error(self): """Mock JSONDecodeError when trying to get JSON form response.""" responses.add(responses.POST, self.dummy_url, body=RequestException("")) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.get_balance()
def test_calls_batch(self): for n in range(2): responses.add( responses.POST, self.dummy_url, status=200, json={"result": "dummy - {}".format(n)}, ) client = AuthServiceProxy(self.dummy_url) cases = [["dummy_method_1", {}], ["dummy_method_2", "dummy"]] results = client.batch_(cases) assert len(results) == len(cases)
def verify_monero_signature(address: str, challenge: str, signature: str) -> bool: """Makes a request to wallet RPC to verify address and signature.""" protocol = settings.DJCL_MONERO_WALLET_RPC_PROTOCOL host = settings.DJCL_MONERO_WALLET_RPC_HOST user = settings.DJCL_MONERO_WALLET_RPC_USER pwd = settings.DJCL_MONERO_WALLET_RPC_PASS wallet_rpc = AuthServiceProxy(f"{protocol}://{user}:{pwd}@{host}/json_rpc") result = wallet_rpc.verify( {"data": challenge, "address": address, "signature": signature} ) return result.get("good", False)
def daemon_rpc_status_check( conn=None, url=URL, port=RPC_PORT, user=USER, passwd=PASSWD ): """Check daemon status. Uses Monero daemon RPC 'hard_fork_info'. """ error = None response = None status = DAEMON_STATUS_UNKNOWN version = -1 try: if not conn: conn = AuthServiceProxy( f"http://{user}@{url}:{port}/json_rpc", password=f"{passwd}", timeout=HTTP_TIMEOUT, ) logger.info(f"Checking '{url}:{port}'.") hard_fork_info = conn.hard_fork_info() status = hard_fork_info["status"] version = hard_fork_info["version"] response = {} except (ValueError, JSONRPCException, RequestException) as e: error = {"error": str(e)} if response is None: if not error: error = {"error": f"No response."} response = {"status": status, "version": version} response.update({"host": f"{url}:{port}"}) if status in (DAEMON_STATUS_ERROR, DAEMON_STATUS_UNKNOWN) or error: if status == DAEMON_STATUS_ERROR: message = f"Status is '{status}'." else: message = f"Cannot determine status." data = {"message": message} if not error: error = {"error": message} data.update(error) response.update({"error": data}) logger.error(json.dumps(data)) return response
def make_transaction(destination_address, amount): """Makes a transaction to the given address. :param destination_address: the wallet address to send WAZN to :param amount: the amount of WAZN to send :returns: the complete transaction object including user's IP address :raises RpcConnectionError: in case of a connection error to the rpc :raises ValueError: in case the JSON returned is bad """ # send xmr to given destination_address recipients = [{"address": destination_address, "amount": amount}] # transfer parameters params = {"destinations": recipients, "mixin": settings.DEFAULT_MIXIN} if len(destination_address) == 95: # payment id payment_id = tools.generate_xmr_payment_id_long() params.update({"payment_id": payment_id}) # get the wallet's address rpc_connection = AuthServiceProxy("http://{0}:{1}/json_rpc".format( settings.WALLET_HOST, settings.WALLET_PORT)) result = None try: result = rpc_connection.transfer_split(params) except ( requests.HTTPError, requests.ConnectionError, JSONRPCException, ) as e: logger.error("RPC Error on making transaction" + str(e)) raise RpcConnectionError(str(e)) # transfer returns a single tx_hash # tarnsfer_split returns a list of tx_hash -> tx_hash_list transaction_id = result.get("tx_hash_list", list()) # check tx_hash_list key if not transaction_id: raise ValueError("Error with: {0}".format(result)) transaction = dict() transaction.update({ "transaction_id": ",".join(transaction_id), "destination_address": destination_address, "amount": amount, }) return transaction
def post(self, request): """Requests services and gathers information on daemons. """ serializer = InfoPostSerializer(data=request.data) if serializer.is_valid(): # get the current balance rpc_connection = AuthServiceProxy('http://{0}:{1}/json_rpc'.format( serializer.data.get('node_url'), settings.WHICH_DAEMON_PORT)) result = None try: result = rpc_connection.which_method() except (requests.HTTPError, requests.ConnectionError, JSONRPCException) as e: logger.error('RPC Error ' + str(e)) response_info = dict({ "nettype": result.get("nettype"), "offline": result.get("offline"), "status": result.get("status"), "height": result.get("height"), "top_block_hash": result.get("top_block_hash"), "rpc_connections_count": result.get("rpc_connections_count"), }) result = None try: result = rpc_connection.which_method() except (requests.HTTPError, requests.ConnectionError, JSONRPCException) as e: logger.error('RPC Error ' + str(e)) response_fee = dict({ "fee": result.get("fee"), }) result = None try: result = rpc_connection.which_method() except (requests.HTTPError, requests.ConnectionError, JSONRPCException) as e: logger.error('RPC Error ' + str(e)) response_version = dict({ "version": result.get("version"), }) response = dict() response[settings.DAEMON_MAINNET_PORT] = dict() response[settings.DAEMON_MAINNET_PORT].update(response_info) response[settings.DAEMON_MAINNET_PORT].update(response_fee) response[settings.DAEMON_MAINNET_PORT].update(response_version) try: response.update( get_more_node_info( url=TESTNET_INFO_HOST + TESTNET_INFO_ENDPOINT, node_url=serializer.data.get('node_url'))) except (requests.HTTPError, requests.ConnectionError, requests.RequestException) as e: logger.warn(str(e)) return JsonResponse(response) logger.error(serializer.errors) return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
from monerorpc.authproxy import AuthServiceProxy, JSONRPCException import logging logging.basicConfig() logging.getLogger("MoneroRPC").setLevel(logging.DEBUG) log = logging.getLogger("wallet-rpc-lib") rpc = AuthServiceProxy('http://*****:*****@127.0.0.1:38083/json_rpc') #rpc = AuthServiceProxy('http://127.0.0.1:38083/json_rpc') try: rpc.get_balance() params = {"account_index": 0, "address_indices": [0, 1]} rpc.get_balance(params) destinations = { "destinations": [{ "address": "59McWTPGc745SRWrSMoh8oTjoXoQq6sPUgKZ66dQWXuKFQ2q19h9gvhJNZcFTizcnT12r63NFgHiGd6gBCjabzmzHAMoyD6", "amount": 1 }], "mixin": 10 } rpc.transfer(destinations) except (JSONRPCException) as e: log.error(e)
from monerorpc.authproxy import AuthServiceProxy, JSONRPCException import logging logging.basicConfig() logging.getLogger("MoneroRPC").setLevel(logging.DEBUG) log = logging.getLogger("wallet-rpc-lib") rpc = AuthServiceProxy('http://*****:*****@127.0.0.1:18081/json_rpc') #rpc = AuthServiceProxy('http://127.0.0.1:18081/json_rpc') try: rpc.get_info() except (JSONRPCException) as e: log.error(e)
from monerorpc.authproxy import AuthServiceProxy, JSONRPCException import logging import pprint logging.basicConfig() logging.getLogger("MoneroRPC").setLevel(logging.DEBUG) log = logging.getLogger("wallet-rpc-lib") rpc = AuthServiceProxy('http://*****:*****@127.0.0.1:38083/json_rpc') #rpc = AuthServiceProxy('http://127.0.0.1:38083/json_rpc') try: params={"account_index":0,"address_indices":[0,1]} result = rpc.batch_([ ["get_balance"], ["get_balance", params] ]) pprint.pprint(result) destinations = {"destinations": [{"address": "59McWTPGc745SRWrSMoh8oTjoXoQq6sPUgKZ66dQWXuKFQ2q19h9gvhJNZcFTizcnT12r63NFgHiGd6gBCjabzmzHAMoyD6", "amount": 1}], "mixin": 10} result = rpc.batch_([ ["transfer", destinations], ["get_balance"] ]) pprint.pprint(result) except (JSONRPCException) as e: log.error(e)
def test_good_call(self): responses.add(responses.POST, self.dummy_url, json={"result": "dummy"}) client = AuthServiceProxy(self.dummy_url) resp = client.status() assert resp == "dummy"
def get_last_and_next_hardfork( # noqa: C901 url=URL_DEFAULT, branch=BRANCH_NAME, daemon_address=DAEMON_ADDRESS, monero_network=MONERO_NETWORK, timeout=TIMEOUT, ): url = url.format(branch_name=branch) log.debug(url) if monero_network not in NETWORK_MODES: log.error(f"This is no known monero network mode '{monero_network}'.") sys.exit(1) log.info( f"Getting hard fork versions for '{monero_network}' from '{url}'." ) log.info(f"Getting daemon info from '{daemon_address}'.") lines = [] interesting = defaultdict(list) try: response = requests.get(url, timeout=timeout) log.debug(response.status_code) log.debug(response.text) if response.status_code != 200: log.error( f"Received HTTP status code '{response.status_code}' for '{url}' with '{response.text}'." ) sys.exit(1) code = response.text start_line = re.compile(NETWORK_RE[monero_network], re.IGNORECASE) end_line = re.compile(END, re.IGNORECASE) info_line = re.compile(INFO, re.IGNORECASE) interesting_range = False lines = code.split("\n") except (RequestException) as e: log.error(f"Cannot get information from '{url}', because: '{str(e)}'.") api_responsive = True rpc_connection = AuthServiceProxy( service_url=daemon_address, timeout=timeout ) for i, line in enumerate(lines): line = line.strip() if line: if start_line.match(line): interesting_range = True if end_line.match(line) and interesting_range: interesting_range = False break if interesting_range: info_match = info_line.match(line) if info_match: fork_info = list(info_line.finditer(line)) version = fork_info[0].group(1) block = fork_info[0].group(2) difficulty = ( fork_info[0] .group(4) .translate({ord(" "): None, ord("}"): None}) ) # Get block header by given activation block height. # This info is used to get the actual hard fork date by block timestamp. result = None try: if api_responsive: result = rpc_connection.get_block_header_by_height( {"height": block} ) except (JSONRPCException) as e: log.error( f"Cannot get info from '{daemon_address}', because: '{str(e)}'." ) api_responsive = False if result: timestamp = result["block_header"]["timestamp"] date = datetime.fromtimestamp( float(timestamp) ).strftime("%b %d %Y ") + str(timezone.utc) else: date = "---" # add to list interesting[f"Version {version}"].append(date) interesting[f"Version {version}"].append(block) interesting[f"Version {version}"].append(difficulty) return interesting
from monerorpc.authproxy import AuthServiceProxy, JSONRPCException import logging logging.basicConfig() logging.getLogger("MoneroRPC").setLevel(logging.DEBUG) log = logging.getLogger("wallet-rpc-lib") rpc = AuthServiceProxy("http://*****:*****@127.0.0.1:18081/json_rpc") # rpc = AuthServiceProxy('http://127.0.0.1:18081/json_rpc') try: rpc.get_block_count() params = [2] hash = rpc.on_get_block_hash(params) print(hash) except (JSONRPCException) as e: log.error(e)
def daemon_last_block_check( conn=None, url=URL, port=RPC_PORT, user=USER, passwd=PASSWD, offset=OFFSET, offset_unit=OFFSET_UNIT, ): """Check last block status. Uses an offset to determine an 'old'/'outdated' last block. """ error = None response = None block_recent = False status = DAEMON_STATUS_UNKNOWN last_block_timestamp = -1 timestamp_obj = None block_age = None last_block_hash = "---" check_timestamp = datetime.datetime.utcnow().replace(microsecond=0) try: if not conn: conn = AuthServiceProxy( f"http://{user}@{url}:{port}/json_rpc", password=f"{passwd}", timeout=HTTP_TIMEOUT, ) logger.info(f"Checking '{url}:{port}'.") last_block_header = conn.get_last_block_header()["block_header"] last_block_timestamp = float(last_block_header["timestamp"]) timestamp_obj = datetime.datetime.utcfromtimestamp( last_block_timestamp ) last_block_hash = last_block_header["hash"] block_recent, offset, offset_unit = is_timestamp_within_offset( timestamp=timestamp_obj, now=check_timestamp, offset=offset, offset_unit=offset_unit, ) status = DAEMON_STATUS_OK if block_recent else DAEMON_STATUS_ERROR block_age = str(check_timestamp - timestamp_obj) response = {} except (ValueError, JSONRPCException, RequestException) as e: error = {"error": str(e)} if response is None: if not error: error = {"error": f"No response."} response = { "hash": last_block_hash, "block_age": block_age if block_age else -1, "block_timestamp": timestamp_obj.isoformat() if timestamp_obj else "---", "check_timestamp": check_timestamp.isoformat(), "status": status, "block_recent": block_recent, "block_recent_offset": offset, "block_recent_offset_unit": offset_unit, } response.update({"host": f"{url}:{port}"}) if status in (DAEMON_STATUS_ERROR, DAEMON_STATUS_UNKNOWN) or error: if status == DAEMON_STATUS_ERROR: message = f"Last block's timestamp is older than '{offset} [{offset_unit}]'." else: message = f"Cannot determine status." data = {"message": message} if not error: error = {"error": f"Last block's age is '{block_age}'."} data.update(error) response.update({"error": data}) logger.error(json.dumps(data)) return response
def test_http_error_raises_error(self, code): responses.add(responses.POST, self.dummy_url, status=code) client = AuthServiceProxy(self.dummy_url) with pytest.raises(JSONRPCException): client.dummy_method()
def test_other_request_error(self): """Mock other errors connecting to server.""" responses.add(responses.POST, self.dummy_url, body="<html></html>") client = AuthServiceProxy(self.dummy_url) with pytest.raises(ValueError): client.get_balance()