diff --git a/lib/ucoinpy/api/bma/__init__.py b/lib/ucoinpy/api/bma/__init__.py index d126a82a74357e4acacdc898e432b48b9f4270c1..464d65613523d4364e4de9698c4c824e7b81f301 100644 --- a/lib/ucoinpy/api/bma/__init__.py +++ b/lib/ucoinpy/api/bma/__init__.py @@ -20,11 +20,12 @@ __all__ = ['api'] __author__ = 'Caner Candan' -__version__ = '0.10.0' +__version__ = '0.11.0' __nonsense__ = 'uCoin' -import requests, logging, json -# import pylibscrypt +PROTOCOL_VERSION = "1" + +import aiohttp, requests, asyncio, logging, json logger = logging.getLogger("ucoin") @@ -93,14 +94,13 @@ class API(object): def __get__(self, **kwargs): """interface purpose for GET request""" - pass def __post__(self, **kwargs): """interface purpose for POST request""" - pass + @asyncio.coroutine def requests_get(self, path, **kwargs): """ Requests GET wrapper in order to use API parameters. @@ -108,12 +108,12 @@ class API(object): Arguments: - `path`: the request path """ + logging.debug("Request : {0}".format(self.reverse_url(path))) + response = yield from asyncio.wait_for(aiohttp.get(self.reverse_url(path), params=kwargs, + headers=self.headers), 15) - response = requests.get(self.reverse_url(path), params=kwargs, - headers=self.headers, timeout=15) - - if response.status_code != 200: - raise ValueError('status code != 200 => %d (%s)' % (response.status_code, response.text)) + if response.status != 200: + raise ValueError('status code != 200 => %d (%s)' % (response.status, (yield from response.text()))) return response @@ -128,17 +128,13 @@ class API(object): kwargs['self'] = kwargs.pop('self_') logging.debug("POST : {0}".format(kwargs)) - response = requests.post(self.reverse_url(path), data=kwargs, headers=self.headers, + response = yield from asyncio.wait_for( + aiohttp.post(self.reverse_url(path), data=kwargs, headers=self.headers), timeout=15) - if response.status_code != 200: - raise ValueError('status code != 200 => %d (%s)' % (response.status_code, response.text)) + if response.status != 200: + raise ValueError('status code != 200 => %d (%s)' % (response.status, (yield from (response.text())))) return response - def merkle_easy_parser(self, path, begin=None, end=None): - root = self.requests_get(path, leaves='true').json() - for leaf in root['leaves'][begin:end]: - yield self.requests_get(path, leaf=leaf).json()['leaf'] - -from . import network, blockchain, tx, wot, node +from . import network, blockchain, tx, wot, node, ud diff --git a/lib/ucoinpy/api/bma/blockchain/__init__.py b/lib/ucoinpy/api/bma/blockchain/__init__.py index f594d7f1b91aaaeb0717d6a2d77ca469478e275e..8edd830d857737fa4e104d9e4d7b9ed555efa9e9 100644 --- a/lib/ucoinpy/api/bma/blockchain/__init__.py +++ b/lib/ucoinpy/api/bma/blockchain/__init__.py @@ -30,7 +30,8 @@ class Parameters(Blockchain): """GET the blockchain parameters used by this node.""" def __get__(self, **kwargs): - return self.requests_get('/parameters', **kwargs).json() + r = yield from self.requests_get('/parameters', **kwargs) + return (yield from r.json()) class Membership(Blockchain): @@ -42,11 +43,13 @@ class Membership(Blockchain): def __post__(self, **kwargs): assert 'membership' in kwargs - return self.requests_post('/membership', **kwargs).json() + r = yield from self.requests_post('/membership', **kwargs) + return (yield from r.text()) def __get__(self, **kwargs): assert self.search is not None - return self.requests_get('/memberships/%s' % self.search, **kwargs).json() + r = yield from self.requests_get('/memberships/%s' % self.search, **kwargs) + return (yield from r.json()) class Block(Blockchain): @@ -66,20 +69,23 @@ class Block(Blockchain): def __get__(self, **kwargs): assert self.number is not None - return self.requests_get('/block/%d' % self.number, **kwargs).json() + r = yield from self.requests_get('/block/%d' % self.number, **kwargs) + return (yield from r.json()) def __post__(self, **kwargs): assert 'block' in kwargs assert 'signature' in kwargs - return self.requests_post('/block', **kwargs).json() + r = yield from self.requests_post('/block', **kwargs) + return (yield from r.text()) class Current(Blockchain): """GET, same as block/[number], but return last accepted block.""" def __get__(self, **kwargs): - return self.requests_get('/current', **kwargs).json() + r = yield from self.requests_get('/current', **kwargs) + return (yield from r.json()) class Hardship(Blockchain): @@ -99,60 +105,69 @@ class Hardship(Blockchain): def __get__(self, **kwargs): assert self.fingerprint is not None - return self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs).json() + r = yield from self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs) + return (yield from r.json()) class Newcomers(Blockchain): """GET, return block numbers containing newcomers.""" def __get__(self, **kwargs): - return self.requests_get('/with/newcomers', **kwargs).json() + r = yield from self.requests_get('/with/newcomers', **kwargs) + return (yield from r.json()) class Certifications(Blockchain): """GET, return block numbers containing certifications.""" def __get__(self, **kwargs): - return self.requests_get('/with/certs', **kwargs).json() + r = yield from self.requests_get('/with/certs', **kwargs) + return (yield from r.json()) class Joiners(Blockchain): """GET, return block numbers containing joiners.""" def __get__(self, **kwargs): - return self.requests_get('/with/joiners', **kwargs).json() + r = yield from self.requests_get('/with/joiners', **kwargs) + return (yield from r.json()) class Actives(Blockchain): """GET, return block numbers containing actives.""" def __get__(self, **kwargs): - return self.requests_get('/with/actives', **kwargs).json() + r = yield from self.requests_get('/with/actives', **kwargs) + return (yield from r.json()) class Leavers(Blockchain): """GET, return block numbers containing leavers.""" def __get__(self, **kwargs): - return self.requests_get('/with/leavers', **kwargs).json() + r = yield from self.requests_get('/with/leavers', **kwargs) + return (yield from r.json()) class Excluded(Blockchain): """GET, return block numbers containing excluded.""" def __get__(self, **kwargs): - return self.requests_get('/with/excluded', **kwargs).json() + r = yield from self.requests_get('/with/excluded', **kwargs) + return (yield from r.json()) class UD(Blockchain): """GET, return block numbers containing universal dividend.""" def __get__(self, **kwargs): - return self.requests_get('/with/ud', **kwargs).json() + r = yield from self.requests_get('/with/ud', **kwargs) + return (yield from r.json()) class TX(Blockchain): """GET, return block numbers containing transactions.""" def __get__(self, **kwargs): - return self.requests_get('/with/tx', **kwargs).json() + r = yield from self.requests_get('/with/tx', **kwargs) + return (yield from r.json()) diff --git a/lib/ucoinpy/api/bma/network/__init__.py b/lib/ucoinpy/api/bma/network/__init__.py index 3d6c73ec6eebd9d0f96f32c94457c0b4084e3685..860674c98ea6749d7593f2ff7da10dd6f0f6fff0 100644 --- a/lib/ucoinpy/api/bma/network/__init__.py +++ b/lib/ucoinpy/api/bma/network/__init__.py @@ -30,6 +30,7 @@ class Peering(Network): """GET peering information about a peer.""" def __get__(self, **kwargs): - return self.requests_get('/peering', **kwargs).json() + r = yield from self.requests_get('/peering', **kwargs) + return (yield from r.json()) from . import peering diff --git a/lib/ucoinpy/api/bma/network/peering/__init__.py b/lib/ucoinpy/api/bma/network/peering/__init__.py index 3ad7cde34997eed39cced842659f2af92b0fe37d..8150cec1ac6b6e8cb7245560fc8f0f0d664937f9 100644 --- a/lib/ucoinpy/api/bma/network/peering/__init__.py +++ b/lib/ucoinpy/api/bma/network/peering/__init__.py @@ -32,13 +32,15 @@ class Peers(Base): def __get__(self, **kwargs): """creates a generator with one peering entry per iteration.""" - return self.merkle_easy_parser('/peers') + r = yield from self.requests_get('/peers', **kwargs) + return (yield from r.json()) def __post__(self, **kwargs): assert 'entry' in kwargs assert 'signature' in kwargs - return self.requests_post('/peers', **kwargs).json() + r = yield from self.requests_post('/peers', **kwargs) + return (yield from r.json()) class Status(Base): @@ -48,4 +50,5 @@ class Status(Base): assert 'status' in kwargs assert 'signature' in kwargs - return self.requests_post('/status', **kwargs).json() + r = yield from self.requests_post('/status', **kwargs) + return (yield from r.json()) diff --git a/lib/ucoinpy/api/bma/node/__init__.py b/lib/ucoinpy/api/bma/node/__init__.py index f2b040f23e8300f16687016225c5f413ad5c9ebf..f156578757aeb3056e404490a1629ce1c3659790 100644 --- a/lib/ucoinpy/api/bma/node/__init__.py +++ b/lib/ucoinpy/api/bma/node/__init__.py @@ -33,5 +33,6 @@ class Summary(Node): super(Summary, self).__init__(connection_handler, module) def __get__(self, **kwargs): - return self.requests_get('/summary', **kwargs).json() + r = yield from self.requests_get('/summary', **kwargs) + return (yield from r.json()) diff --git a/lib/ucoinpy/api/bma/tx/__init__.py b/lib/ucoinpy/api/bma/tx/__init__.py index 0242efaec698c54a9f53307b5cd0931101477ec0..8199d2d8d49a56016424c14b30a653f7211b5f5b 100644 --- a/lib/ucoinpy/api/bma/tx/__init__.py +++ b/lib/ucoinpy/api/bma/tx/__init__.py @@ -26,13 +26,26 @@ class Tx(API): super(Tx, self).__init__(connection_handler, module) +class History(Tx): + """Get transaction sources.""" + def __init__(self, conn_handler, pubkey, module='tx'): + super(Tx, self).__init__(conn_handler, module) + self.pubkey = pubkey + + def __get__(self, **kwargs): + assert self.pubkey is not None + r = yield from self.requests_get('/history/%s' % self.pubkey, **kwargs) + return (yield from r.json()) + + class Process(Tx): """POST a transaction.""" def __post__(self, **kwargs): assert 'transaction' in kwargs - return self.requests_post('/process', **kwargs).json() + r = yield from self.requests_post('/process', **kwargs) + return (yield from r.text()) class Sources(Tx): @@ -43,4 +56,7 @@ class Sources(Tx): def __get__(self, **kwargs): assert self.pubkey is not None - return self.requests_get('/sources/%s' % self.pubkey, **kwargs).json() + r = yield from self.requests_get('/sources/%s' % self.pubkey, **kwargs) + return (yield from r.json()) + +from . import history \ No newline at end of file diff --git a/lib/ucoinpy/api/bma/wot/__init__.py b/lib/ucoinpy/api/bma/wot/__init__.py index ea9b9a236959a0def6cc9e28daac73a1df6f1446..ca9c97bcab3433eda75a28fc17c4d3b8b5d8de05 100644 --- a/lib/ucoinpy/api/bma/wot/__init__.py +++ b/lib/ucoinpy/api/bma/wot/__init__.py @@ -34,7 +34,8 @@ class Add(WOT): assert 'self_' in kwargs assert 'other' in kwargs - return self.requests_post('/add', **kwargs).json() + r = yield from self.requests_post('/add', **kwargs) + return (yield from r.text()) class Revoke(WOT): @@ -44,7 +45,8 @@ class Revoke(WOT): assert 'pubkey' in kwargs assert 'self_' in kwargs - return self.requests_post('/revoke', **kwargs).json() + r = yield from self.requests_post('/revoke', **kwargs) + return (yield from r.text()) class Lookup(WOT): @@ -58,7 +60,8 @@ class Lookup(WOT): def __get__(self, **kwargs): assert self.search is not None - return self.requests_get('/lookup/%s' % self.search, **kwargs).json() + r = yield from self.requests_get('/lookup/%s' % self.search, **kwargs) + return (yield from r.json()) class CertifiersOf(WOT): @@ -72,7 +75,8 @@ class CertifiersOf(WOT): def __get__(self, **kwargs): assert self.search is not None - return self.requests_get('/certifiers-of/%s' % self.search, **kwargs).json() + r = yield from self.requests_get('/certifiers-of/%s' % self.search, **kwargs) + return (yield from r.json()) class CertifiedBy(WOT): @@ -86,7 +90,8 @@ class CertifiedBy(WOT): def __get__(self, **kwargs): assert self.search is not None - return self.requests_get('/certified-by/%s' % self.search, **kwargs).json() + r = yield from self.requests_get('/certified-by/%s' % self.search, **kwargs) + return (yield from r.json()) class Members(WOT): @@ -96,4 +101,5 @@ class Members(WOT): super(WOT, self).__init__(connection_handler, module) def __get__(self, **kwargs): - return self.requests_get('/members', **kwargs).json() + r = yield from self.requests_get('/members', **kwargs) + return (yield from r.json()) diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 35bb49181f3623346d6aca6b2e982858cefea9b5..d14e03b659ab45218e97f4f45eb2052637dd826b 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -21,8 +21,8 @@ from .community import Community from .registry import LocalState from ..tools.exceptions import ContactAlreadyExists from ..tools.decorators import asyncify -from ..core.net.api import bma as qtbma -from ..core.net.api.bma import PROTOCOL_VERSION +from ucoinpy.api import bma +from ucoinpy.api.bma import PROTOCOL_VERSION class Account(QObject): @@ -295,38 +295,19 @@ class Account(QObject): key = SigningKey(self.salt, password) selfcert.sign([key]) logging.debug("Key publish : {0}".format(selfcert.signed_raw())) - replies = community.bma_access.broadcast(qtbma.wot.Add, {}, {'pubkey': self.pubkey, + try: + error = 0 + replies = yield from community.bma_access.broadcast(bma.wot.Add, {}, {'pubkey': self.pubkey, 'self_': selfcert.signed_raw(), 'other': ""}) - for r in replies: - r.finished.connect(lambda reply=r: self.__handle_selfcert_replies(replies, reply)) - - def __handle_selfcert_replies(self, replies, reply): - """ - Handle the reply, if the request was accepted, disconnect - all other replies - - :param QNetworkReply reply: The reply of this handler - :param list of QNetworkReply replies: All request replies - :return: - """ - strdata = bytes(reply.readAll()).decode('utf-8') - logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata)) - if reply.error() == QNetworkReply.NoError: - for r in replies: - try: - r.disconnect() - except TypeError as e: - if "disconnect()" in str(e): - logging.debug("Could not disconnect a reply") - else: - raise - self.selfcert_broadcasted.emit() - else: - for r in replies: - if not r.isFinished() or r.error() == QNetworkReply.NoError: - return - self.broadcast_error.emit(r.error(), strdata) + except ValueError as e: + error += 1 + error_msg = str(e) + finally: + if error < len(replies): + self.selfcert_broadcasted.emit() + else: + self.broadcast_error.emit(0, error_msg) @asyncio.coroutine def send_membership(self, password, community, mstype): @@ -351,37 +332,18 @@ class Account(QObject): key = SigningKey(self.salt, password) membership.sign([key]) logging.debug("Membership : {0}".format(membership.signed_raw())) - replies = community.bma_access.broadcast(qtbma.blockchain.Membership, {}, + try: + error = 0 + replies = yield from community.bma_access.broadcast(bma.blockchain.Membership, {}, {'membership': membership.signed_raw()}) - for r in replies: - r.finished.connect(lambda reply=r: self.__handle_membership_replies(replies, reply)) - - def __handle_membership_replies(self, replies, reply): - """ - Handle the reply, if the request was accepted, disconnect - all other replies - - :param QNetworkReply reply: The reply of this handler - :param list of QNetworkReply replies: All request replies - :return: - """ - strdata = bytes(reply.readAll()).decode('utf-8') - logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata)) - if reply.error() == QNetworkReply.NoError: - for r in replies: - try: - r.disconnect() - except TypeError as e: - if "disconnect()" in str(e): - logging.debug("Could not disconnect a reply") - else: - raise - self.membership_broadcasted.emit() - else: - for r in replies: - if not r.isFinished() or r.error() == QNetworkReply.NoError: - return - self.broadcast_error.emit(r.error(), strdata) + except ValueError as e: + error += 1 + error_msg = str(e) + finally: + if error < len(replies): + self.membership_broadcasted.emit() + else: + self.broadcast_error.emit(0, error_msg) @asyncio.coroutine def certify(self, password, community, pubkey): @@ -409,36 +371,17 @@ class Account(QObject): 'self_': selfcert.signed_raw(), 'other': "{0}\n".format(certification.inline())} logging.debug("Posted data : {0}".format(data)) - replies = community.bma_access.broadcast(qtbma.wot.Add, {}, data) - for r in replies: - r.finished.connect(lambda reply=r: self.__handle_certification_reply(replies, reply)) - - def __handle_certification_reply(self, replies, reply): - """ - Handle the reply, if the request was accepted, disconnect - all other replies - - :param QNetworkReply reply: The reply of this handler - :param list of QNetworkReply replies: All request replies - :return: - """ - strdata = bytes(reply.readAll()).decode('utf-8') - logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata)) - if reply.error() == QNetworkReply.NoError: - for r in replies: - try: - r.disconnect() - except TypeError as e: - if "disconnect()" in str(e): - logging.debug("Could not disconnect a reply") - else: - raise - self.certification_broadcasted.emit() - else: - for r in replies: - if not r.isFinished() or r.error() == QNetworkReply.NoError: - return - self.broadcast_error.emit(r.error(), strdata) + try: + error = 0 + responses = yield from community.bma_access.broadcast(bma.wot.Add, {}, data) + except ValueError as e: + error += 1 + error_msg = str(e) + finally: + if error < len(responses): + self.certification_broadcasted.emit() + else: + self.broadcast_error.emit(0, error_msg) @asyncio.coroutine def revoke(self, password, community): @@ -465,36 +408,17 @@ class Account(QObject): 'sig': revocation.signatures[0] } logging.debug("Posted data : {0}".format(data)) - replies = community.broadcast(qtbma.wot.Revoke, {}, data) - for r in replies: - r.finished.connect(lambda reply=r: self.__handle_certification_reply(replies, reply)) - - def __handle_revoke_reply(self, replies, reply): - """ - Handle the reply, if the request was accepted, disconnect - all other replies - - :param QNetworkReply reply: The reply of this handler - :param list of QNetworkReply replies: All request replies - :return: - """ - strdata = bytes(reply.readAll()).decode('utf-8') - logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata)) - if reply.error() == QNetworkReply.NoError: - for r in replies: - try: - r.disconnect() - except TypeError as e: - if "disconnect()" in str(e): - logging.debug("Could not disconnect a reply") - else: - raise - self.revoke_broadcasted.emit() - else: - for r in replies: - if not r.isFinished() or r.error() == QNetworkReply.NoError: - return - self.broadcast_error.emit(r.error(), strdata) + try: + error = 0 + replies = yield from community.broadcast(bma.wot.Revoke, {}, data) + except ValueError as e: + error += 1 + error_msg = str(e) + finally: + if error < len(replies): + self.revoke_broadcasted.emit() + else: + self.broadcast_error.emit(error_msg) def start_coroutines(self): for c in self.communities: diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 18be5087c8972ee7f4a8fe1999eaaed8d5f6754e..07dd45b6e07aff5fe01b265b8ce988b837e187dc 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -15,7 +15,8 @@ from PyQt5.QtCore import QObject, pyqtSignal from ..tools.exceptions import NoPeerAvailable from .net.network import Network -from .net.api import bma as qtbma +from ucoinpy.api import bma +from ucoinpy.documents.block import Block from .net.api.bma.access import BmaAccess @@ -140,7 +141,7 @@ class Community(QObject): :return: The computed UD or 1 if no UD was generated. """ block = yield from self.get_ud_block() - if block and block != qtbma.blockchain.Block.null_value: + if block and block != bma.blockchain.Block.null_value: return math.ceil( max( self.dividend, @@ -160,14 +161,14 @@ class Community(QObject): :param int x: Get the 'x' older block with UD in it :return: The last block with universal dividend. """ - udblocks = yield from self.bma_access.future_request(qtbma.blockchain.UD) + udblocks = yield from self.bma_access.future_request(bma.blockchain.UD) blocks = udblocks['result']['blocks'] if len(blocks) > 0: index = len(blocks)-(1+x) if index < 0: index = 0 block_number = blocks[index] - block = yield from self.bma_access.future_request(qtbma.blockchain.Block, + block = yield from self.bma_access.future_request(bma.blockchain.Block, req_args={'number': block_number}) return block else: @@ -182,7 +183,7 @@ class Community(QObject): """ # Get cached block by block number block_number = self.network.latest_block_number - block = yield from self.bma_access.future_request(self, qtbma.blockchain.Block, + block = yield from self.bma_access.future_request(self, bma.blockchain.Block, req_args={'number': block_number}) return block['monetaryMass'] @@ -196,7 +197,7 @@ class Community(QObject): try: # Get cached block by block number block_number = self.network.latest_block_number - block = yield from self.bma_access.future_request(qtbma.blockchain.Block, + block = yield from self.bma_access.future_request(bma.blockchain.Block, req_args={'number': block_number}) return block['membersCount'] except ValueError as e: @@ -230,7 +231,7 @@ class Community(QObject): """ Return community parameters in bma format """ - return self.bma_access.future_request(qtbma.blockchain.Parameters) + return self.bma_access.future_request(bma.blockchain.Parameters) @asyncio.coroutine def certification_expired(self, certtime): @@ -264,10 +265,10 @@ class Community(QObject): :param int number: The block number. If none, returns current block. """ if number is None: - data = self.bma_access.future_request(qtbma.blockchain.Current) + data = self.bma_access.future_request(bma.blockchain.Current) else: logging.debug("Requesting block {0}".format(number)) - data = self.bma_access.future_request(qtbma.blockchain.Block, + data = self.bma_access.future_request(bma.blockchain.Block, req_args={'number': number}) return data @@ -278,10 +279,16 @@ class Community(QObject): :return: The current block ID as [NUMBER-HASH] format. """ - block = yield from self.bma_access.future_request(qtbma.blockchain.Current) - signed_raw = "{0}{1}\n".format(block['raw'], block['signature']) - block_hash = hashlib.sha1(signed_raw.encode("ascii")).hexdigest().upper() - block_number = block['number'] + try: + block = yield from self.bma_access.future_request(bma.blockchain.Current) + signed_raw = "{0}{1}\n".format(block['raw'], block['signature']) + block_hash = hashlib.sha1(signed_raw.encode("ascii")).hexdigest().upper() + block_number = block['number'] + except ValueError as e: + if '404' in str(e): + block_hash = Block.Empty_Hash + block_number = 0 + return {'number': block_number, 'hash': block_hash} @asyncio.coroutine @@ -291,7 +298,7 @@ class Community(QObject): :return: All members pubkeys. """ - memberships = yield from self.bma_access.future_request(qtbma.wot.Members) + memberships = yield from self.bma_access.future_request(bma.wot.Members) return [m['pubkey'] for m in memberships["results"]] def start_coroutines(self): diff --git a/src/cutecoin/core/net/api/bma/__init__.py b/src/cutecoin/core/net/api/bma/__init__.py index 9e6132c085043cb39514de46798e72763aa138a7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/cutecoin/core/net/api/bma/__init__.py +++ b/src/cutecoin/core/net/api/bma/__init__.py @@ -1,150 +0,0 @@ - - -__all__ = ['api'] - -from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply -from PyQt5.QtCore import QUrl, QUrlQuery, QTimer, QObject, pyqtSlot -import logging -import asyncio -import json - -logger = logging.getLogger("ucoin") - -PROTOCOL_VERSION = "1" - -@asyncio.coroutine -def timeout(reply, seconds): - #logging.debug("Sleep timeout...") - yield from asyncio.sleep(seconds) - if reply.isRunning(): - #logging.debug("Reply aborted because of timeout") - reply.abort() - - -class ConnectionHandler(object): - """Helper class used by other API classes to ease passing server connection information.""" - - def __init__(self, network_manager, server, port): - """ - Arguments: - - `server`: server hostname - - `port`: port number - """ - - self.network_manager = network_manager - self.server = server - self.port = port - - def __str__(self): - return 'connection info: %s:%d' % (self.server, self.port) - - -class API(object): - """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf classes are the API requests.""" - - def __init__(self, conn_handler, module): - """ - Asks a module in order to create the url used then by derivated classes. - - Arguments: - - `module`: module name - - `connection_handler`: connection handler - """ - - self.module = module - self.conn_handler = conn_handler - self.headers = {} - - def reverse_url(self, path): - """ - Reverses the url using self.url and path given in parameter. - - Arguments: - - `path`: the request path - """ - - server, port = self.conn_handler.server, self.conn_handler.port - - url = 'http://%s:%d/%s' % (server, port, self.module) - return url + path - - def get(self, **kwargs): - """wrapper of overloaded __get__ method.""" - - return self.__get__(**kwargs) - - def post(self, **kwargs): - """wrapper of overloaded __post__ method.""" - - logger.debug('do some work with') - - data = self.__post__(**kwargs) - - logger.debug('and send back') - - return data - - def __get__(self, **kwargs): - """interface purpose for GET request""" - - pass - - def __post__(self, **kwargs): - """interface purpose for POST request""" - - pass - - def requests_get(self, path, **kwargs): - """ - Requests GET wrapper in order to use API parameters. - - Arguments: - - `path`: the request path - """ - query = QUrlQuery() - for k,v in kwargs.items(): - query.addQueryItem(k, v); - url = QUrl(self.reverse_url(path)) - url.setQuery(query) - request = QNetworkRequest(url) - logging.debug(url.toString()) - - reply = self.conn_handler.network_manager.get(request) - asyncio.async(timeout(reply, 15)) - - return reply - - def requests_post(self, path, **kwargs): - """ - Requests POST wrapper in order to use API parameters. - - Arguments: - - `path`: the request path - """ - if 'self_' in kwargs: - kwargs['self'] = kwargs.pop('self_') - - logging.debug("POST : {0}".format(kwargs)) - post_data = QUrlQuery() - for k, v in kwargs.items(): - if type(k) is str: - k = k.replace("+", "%2b") - if type(v) is str: - v = v.replace("+", "%2b") - else: - v = json.dumps(v) - v = v.replace("+", "%2b") - post_data.addQueryItem(k, v) - url = QUrl(self.reverse_url(path)) - url.setQuery(post_data) - - request = QNetworkRequest(url) - request.setHeader(QNetworkRequest.ContentTypeHeader, - "application/x-www-form-urlencoded") - reply = self.conn_handler.network_manager.post(request, - post_data.toString(QUrl.FullyEncoded).encode('utf-8')) - logging.debug(url.toString(QUrl.FullyEncoded)) - asyncio.async(timeout(reply, 15)) - return reply - -from . import network, blockchain, tx, wot, ud, node diff --git a/src/cutecoin/core/net/api/bma/access.py b/src/cutecoin/core/net/api/bma/access.py index 1ee9ab476890087366aa0b3bef1750eb580f6749..63e59be08d9f2e033e702418aef6b1dc9088b86f 100644 --- a/src/cutecoin/core/net/api/bma/access.py +++ b/src/cutecoin/core/net/api/bma/access.py @@ -1,11 +1,10 @@ from PyQt5.QtCore import QObject, pyqtSlot from PyQt5.QtNetwork import QNetworkReply -from . import wot -from . import blockchain, ConnectionHandler +from ucoinpy.api.bma import blockchain from .....tools.exceptions import NoPeerAvailable from ..... import __version__ import logging -import json +from aiohttp.errors import ClientError import asyncio import random @@ -112,7 +111,7 @@ class BmaAccess(QObject): ret_data = cached_data['value'] else: need_reload = True - ret_data = request.null_value + ret_data = None return need_reload, ret_data def _update_cache(self, request, req_args, get_args, data): @@ -138,6 +137,7 @@ class BmaAccess(QObject): return True return False + @asyncio.coroutine def future_request(self, request, req_args={}, get_args={}): """ Start a request to the network and returns a future. @@ -148,33 +148,28 @@ class BmaAccess(QObject): :return: The future data :rtype: dict """ - def handle_future_reply(reply): - if reply.error() == QNetworkReply.NoError: - strdata = bytes(reply.readAll()).decode('utf-8') - json_data = json.loads(strdata) - self._update_cache(request, req_args, get_args, json_data) - if not future_data.cancelled(): - future_data.set_result(json_data) - elif not future_data.cancelled(): - future_data.set_result(request.null_value) - - future_data = asyncio.Future() data = self._get_from_cache(request, req_args, get_args) need_reload = data[0] + json_data = data[1] if need_reload: nodes = self._network.synced_nodes if len(nodes) > 0: - node = random.choice(nodes) - conn_handler = node.endpoint.conn_handler(self._network.network_manager) - req = request(conn_handler, **req_args) - reply = req.get(**get_args) - reply.finished.connect(lambda: handle_future_reply(reply)) - else: - raise NoPeerAvailable("", len(nodes)) - else: - future_data.set_result(data[1]) - return future_data + for i in range(0, 6): + node = random.choice(nodes) + conn_handler = node.endpoint.conn_handler() + req = request(conn_handler, **req_args) + try: + json_data = yield from req.get(**get_args) + self._update_cache(request, req_args, get_args, json_data) + return json_data + except ValueError as e: + if '404' in str(e) or '400' in str(e): + raise + continue + except ClientError: + continue + return json_data def simple_request(self, request, req_args={}, get_args={}): """ @@ -188,9 +183,9 @@ class BmaAccess(QObject): nodes = self._network.synced_nodes if len(nodes) > 0: node = random.choice(nodes) - req = request(node.endpoint.conn_handler(self._network.network_manager), **req_args) - reply = req.get(**get_args) - return reply + req = request(node.endpoint.conn_handler(), **req_args) + json_data = yield from req.get(**get_args) + return json_data else: raise NoPeerAvailable("", len(nodes)) @@ -212,8 +207,8 @@ class BmaAccess(QObject): replies = [] for node in nodes: logging.debug("Trying to connect to : " + node.pubkey) - conn_handler = node.endpoint.conn_handler(self._network.network_manager) + conn_handler = node.endpoint.conn_handler() req = request(conn_handler, **req_args) - reply = req.post(**post_args) + reply = yield from req.post(**post_args) replies.append(reply) return tuple(replies) diff --git a/src/cutecoin/core/net/api/bma/blockchain/__init__.py b/src/cutecoin/core/net/api/bma/blockchain/__init__.py deleted file mode 100644 index eecdfa3de4798cc7a24ef953e7ff87bea95fed7c..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/blockchain/__init__.py +++ /dev/null @@ -1,251 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/blockchain") - - -class Blockchain(API): - def __init__(self, conn_handler, module='blockchain'): - super(Blockchain, self).__init__(conn_handler, module) - - -class Parameters(Blockchain): - """GET the blockchain parameters used by this node.""" - - def __get__(self, **kwargs): - return self.requests_get('/parameters', **kwargs) - - null_value = { - 'currency': "", - 'c': 0, - 'dt': 0, - 'ud0': 0, - 'sigDelay': 0, - 'sigValidity': 0, - 'sigQty': 0, - 'sigWoT': 0, - 'msValidity': 0, - 'stepMax': 0, - 'medianTimeBlocks': 0, - 'avgGenTime': 0, - 'dtDiffEval': 0, - 'blocksRot': 0, - 'percentRot': 0 - } - - -class Membership(Blockchain): - """GET/POST a Membership document.""" - - null_value = \ - { - "pubkey": "", - "uid": "", - "sigDate": 0, - "memberships": [] - } - - def __init__(self, conn_handler, search=None): - super().__init__(conn_handler) - self.search = search - - def __post__(self, **kwargs): - assert 'membership' in kwargs - - return self.requests_post('/membership', **kwargs) - - def __get__(self, **kwargs): - assert self.search is not None - return self.requests_get('/memberships/%s' % self.search, **kwargs) - - -class Block(Blockchain): - """GET/POST a block from/to the blockchain.""" - null_value = { - "version": 1, - "nonce": 0, - "number": -1, - "powMin": 0, - "time": 0, - "medianTime": 0, - "membersCount": 0, - "monetaryMass": 0, - "currency": "", - "issuer": "", - "signature": "", - "hash": "", - "previousHash": "", - "previousIssuer": "", - "dividend": 0, - "membersChanges": [], - "identities": [], - "joiners": [], - "actives": [], - "leavers": [], - "excluded": [], - "certifications": [], - "transactions": [], - "raw": "" - } - - def __init__(self, conn_handler, number=None): - """ - Use the number parameter in order to select a block number. - - Arguments: - - `number`: block number to select - """ - - super(Block, self).__init__(conn_handler) - - self.number = number - - def __get__(self, **kwargs): - assert self.number is not None - return self.requests_get('/block/%d' % self.number, **kwargs) - - def __post__(self, **kwargs): - assert 'block' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/block', **kwargs) - - -class Current(Blockchain): - """GET, same as block/[number], but return last accepted block.""" - null_value = { - "version": 1, - "nonce": 0, - "number": -1, - "powMin": 0, - "time": 0, - "medianTime": 0, - "membersCount": 0, - "monetaryMass": 0, - "currency": "", - "issuer": "", - "signature": "", - "hash": "", - "previousHash": None, - "previousIssuer": None, - "dividend": None, - "membersChanges": [], - "identities": [], - "joiners": [], - "actives": [], - "leavers": [], - "excluded": [], - "certifications": [], - "transactions": [], - "raw": "" - } - - def __get__(self, **kwargs): - return self.requests_get('/current', **kwargs) - - -class Hardship(Blockchain): - """GET hardship level for given member's fingerprint for writing next block.""" - - def __init__(self, conn_handler, fingerprint): - """ - Use the number parameter in order to select a block number. - - Arguments: - - `fingerprint`: member fingerprint - """ - - super(Hardship, self).__init__(conn_handler) - - self.fingerprint = fingerprint - - def __get__(self, **kwargs): - assert self.fingerprint is not None - return self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs) - - -class Newcomers(Blockchain): - """GET, return block numbers containing newcomers.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/newcomers', **kwargs) - - -class Certifications(Blockchain): - """GET, return block numbers containing certifications.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/certs', **kwargs) - - -class Joiners(Blockchain): - """GET, return block numbers containing joiners.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/joiners', **kwargs) - - -class Actives(Blockchain): - """GET, return block numbers containing actives.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/actives', **kwargs) - - -class Leavers(Blockchain): - """GET, return block numbers containing leavers.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/leavers', **kwargs) - - -class Excluded(Blockchain): - """GET, return block numbers containing excluded.""" - - def __get__(self, **kwargs): - return self.requests_get('/with/excluded', **kwargs) - - -class UD(Blockchain): - """GET, return block numbers containing universal dividend.""" - null_value = \ - { - "result": - { - "blocks": [] - } - } - - def __get__(self, **kwargs): - return self.requests_get('/with/ud', **kwargs) - - -class TX(Blockchain): - """GET, return block numbers containing transactions.""" - null_value = \ - { - "result": - { - "blocks": [] - } - } - - def __get__(self, **kwargs): - return self.requests_get('/with/tx', **kwargs) diff --git a/src/cutecoin/core/net/api/bma/network/__init__.py b/src/cutecoin/core/net/api/bma/network/__init__.py deleted file mode 100644 index 252219946af9fd6471dd6f20bf3f95659173d19c..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/network/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/network") - - -class Network(API): - def __init__(self, conn_handler, module='network'): - super(Network, self).__init__(conn_handler, module) - - -class Peering(Network): - """GET peering information about a peer.""" - - def __get__(self, **kwargs): - return self.requests_get('/peering', **kwargs) - -from . import peering diff --git a/src/cutecoin/core/net/api/bma/network/peering/__init__.py b/src/cutecoin/core/net/api/bma/network/peering/__init__.py deleted file mode 100644 index 8da405735be29d99eaea8c590d6c328b3d95a954..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/network/peering/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import Network, logging - -logger = logging.getLogger("ucoin/network/peering") - - -class Base(Network): - def __init__(self, conn_handler): - super(Base, self).__init__(conn_handler, 'network/peering') - - -class Peers(Base): - """GET peering entries of every node inside the currency network.""" - - def __get__(self, **kwargs): - """creates a generator with one peering entry per iteration.""" - - return self.requests_get('/peers', **kwargs) - - def __post__(self, **kwargs): - assert 'entry' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/peers', **kwargs) - - -class Status(Base): - """POST a network status document to this node in order notify of its status.""" - - def __post__(self, **kwargs): - assert 'status' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/status', **kwargs) diff --git a/src/cutecoin/core/net/api/bma/node/__init__.py b/src/cutecoin/core/net/api/bma/node/__init__.py deleted file mode 100644 index fc15e1d876f8b5feaa4f4ef7713f746a2fb8d84c..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/node/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/node") - - -class Node(API): - def __init__(self, connection_handler, module='node'): - super(Node, self).__init__(connection_handler, module) - - -class Summary(Node): - """GET Certification data over a member.""" - - def __init__(self, connection_handler, module='node'): - super(Summary, self).__init__(connection_handler, module) - - def __get__(self, **kwargs): - return self.requests_get('/summary', **kwargs) - diff --git a/src/cutecoin/core/net/api/bma/tx/__init__.py b/src/cutecoin/core/net/api/bma/tx/__init__.py deleted file mode 100644 index 22b63d450be93484ef6888a7872aea6e5e1ac8ad..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/tx/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/tx") - - -class Tx(API): - def __init__(self, conn_handler, module='tx'): - super(Tx, self).__init__(conn_handler, module) - - -class Process(Tx): - """POST a transaction.""" - - def __post__(self, **kwargs): - assert 'transaction' in kwargs - - return self.requests_post('/process', **kwargs) - - -class History(Tx): - """Get transaction sources.""" - - null_value = { - "currency": "", - "pubkey": "", - "history": { - "sent": [], - "received": [] - } - } - - def __init__(self, conn_handler, pubkey, module='tx'): - super(Tx, self).__init__(conn_handler, module) - self.pubkey = pubkey - - def __get__(self, **kwargs): - assert self.pubkey is not None - return self.requests_get('/history/%s' % self.pubkey, **kwargs) - - -class Sources(Tx): - """Get transaction sources.""" - - null_value = { - "currency": "", - "pubkey": "", - "sources": - [ - ] - } - - def __init__(self, conn_handler, pubkey, module='tx'): - super(Tx, self).__init__(conn_handler, module) - self.pubkey = pubkey - - def __get__(self, **kwargs): - assert self.pubkey is not None - return self.requests_get('/sources/%s' % self.pubkey, **kwargs) - -from . import history \ No newline at end of file diff --git a/src/cutecoin/core/net/api/bma/tx/history/__init__.py b/src/cutecoin/core/net/api/bma/tx/history/__init__.py deleted file mode 100644 index 471c4579c0eee3ebe9c5b7582e0fa84ad28601e9..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/tx/history/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import History, logging - -logger = logging.getLogger("ucoin/tx") - - -class Blocks(History): - def __init__(self, conn_handler, pubkey, from_, to_, module='tx'): - super(Blocks, self).__init__(conn_handler, pubkey, module) - self.from_ = from_ - self.to_ = to_ - - null_value = { - "hash": "", - "currency": "", - "pubkey": "", - "history": { - "sent": [], - "received": [] - } - } - - def __get__(self, **kwargs): - return self.requests_get('/history/%s/blocks/%s/%s' % (self.pubkey, self.from_, self.to_), **kwargs) diff --git a/src/cutecoin/core/net/api/bma/ud/__init__.py b/src/cutecoin/core/net/api/bma/ud/__init__.py deleted file mode 100644 index 39ef282632a6288d0b103b702e2ef62dfe712235..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/ud/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/ud") - - -class Ud(API): - def __init__(self, conn_handler, module='ud'): - super(Ud, self).__init__(conn_handler, module) - - - -class History(Ud): - """Get UD history.""" - - null_value = { - "currency": "", - "pubkey": "", - "history": { - "history": [] - } - } - - def __init__(self, conn_handler, pubkey, module='ud'): - super(Ud, self).__init__(conn_handler, module) - self.pubkey = pubkey - - def __get__(self, **kwargs): - assert self.pubkey is not None - return self.requests_get('/history/%s' % self.pubkey, **kwargs) diff --git a/src/cutecoin/core/net/api/bma/wot/__init__.py b/src/cutecoin/core/net/api/bma/wot/__init__.py deleted file mode 100644 index 7fb27cffb2a7b36c0e2d8ae31882c73e98952c7e..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/api/bma/wot/__init__.py +++ /dev/null @@ -1,123 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from .. import API, logging - -logger = logging.getLogger("ucoin/wot") - - -class WOT(API): - def __init__(self, conn_handler, module='wot'): - super(WOT, self).__init__(conn_handler, module) - - -class Add(WOT): - """POST Public key data.""" - - def __post__(self, **kwargs): - assert 'pubkey' in kwargs - assert 'self_' in kwargs - assert 'other' in kwargs - - return self.requests_post('/add', **kwargs) - - -class Revoke(WOT): - """POST Public key data.""" - - def __post__(self, **kwargs): - assert 'pubkey' in kwargs - assert 'self_' in kwargs - - return self.requests_post('/revoke', **kwargs) - - -class Lookup(WOT): - """GET Public key data.""" - null_value = \ - { - "partial": False, - "results": [] - } - - def __init__(self, conn_handler, search, module='wot'): - super(WOT, self).__init__(conn_handler, module) - - self.search = search - - def __get__(self, **kwargs): - assert self.search is not None - - return self.requests_get('/lookup/%s' % self.search, **kwargs) - - -class CertifiersOf(WOT): - """GET Certification data over a member.""" - null_value = \ - { - "pubkey": "", - "uid": "", - "isMember": False, - "certifications": [] - } - - def __init__(self, conn_handler, search, module='wot'): - super(WOT, self).__init__(conn_handler, module) - - self.search = search - - def __get__(self, **kwargs): - assert self.search is not None - - return self.requests_get('/certifiers-of/%s' % self.search, **kwargs) - - -class CertifiedBy(WOT): - """GET Certification data from a member.""" - null_value = \ - { - "pubkey": "", - "uid": "", - "isMember": False, - "certifications": [] - } - - def __init__(self, conn_handler, search, module='wot'): - super(WOT, self).__init__(conn_handler, module) - - self.search = search - - def __get__(self, **kwargs): - assert self.search is not None - - return self.requests_get('/certified-by/%s' % self.search, **kwargs) - - -class Members(WOT): - """GET List all current members of the Web of Trust.""" - - null_value = \ - { - "results": [] - } - - def __init__(self, conn_handler, module='wot'): - super(WOT, self).__init__(conn_handler, module) - - def __get__(self, **kwargs): - return self.requests_get('/members', **kwargs) diff --git a/src/cutecoin/core/net/endpoint.py b/src/cutecoin/core/net/endpoint.py deleted file mode 100644 index 7ddbf792520195a42a29522a05cfa5ece496a1f9..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/net/endpoint.py +++ /dev/null @@ -1,76 +0,0 @@ -import re -import ucoinpy -from .api.bma import ConnectionHandler - -HANDLED_API=["BASIC_MERKLED_API"] - -class Endpoint(): - """ - Describing endpoints - """ - def __init__(self, pyendpoint): - self.pyendpoint = pyendpoint - - @staticmethod - def from_inline(inline): - for api in HANDLED_API: - if (inline.startswith(api)): - if (api == "BASIC_MERKLED_API"): - return BMAEndpoint.from_inline(inline) - return UnknownEndpoint.from_inline(inline) - - @property - def server(self): - return self.pyendpoint.server - - @property - def ipv4(self): - return self.pyendpoint.ipv4 - - @property - def ipv6(self): - return self.pyendpoint.ipv6 - - @property - def port(self): - return self.pyendpoint.port - - -class UnknownEndpoint(Endpoint): - - def __init__(self, pyendpoint): - super().__init__(pyendpoint) - - @classmethod - def from_inline(cls, inline): - endpoint = ucoinpy.documents.peer.UnknownEndpoint.from_inline(inline) - return cls(endpoint) - - def inline(self): - self.pyendpoint.inline() - - -class BMAEndpoint(Endpoint): - re_inline = re.compile('^BASIC_MERKLED_API(?: ([a-z0-9-_.]*(?:.[a-zA-Z])))?(?: ((?:[0-9.]{1,4}){4}))?(?: ((?:[0-9a-f:]{4,5}){4,8}))?(?: ([0-9]+))$') - - def __init__(self, pyendpoint): - super().__init__(pyendpoint) - - @classmethod - def from_inline(cls, inline): - endpoint = ucoinpy.documents.peer.BMAEndpoint.from_inline(inline) - return cls(endpoint) - - def inline(self): - return self.pyendpoint.inline() - - def conn_handler(self, network_manager): - if self.server: - return ConnectionHandler(network_manager, - self.pyendpoint.server, self.pyendpoint.port) - elif self.ipv4: - return ConnectionHandler(network_manager, self.pyendpoint.ipv4, - self.pyendpoint.port) - else: - return ConnectionHandler(network_manager, - self.pyendpoint.ipv6, self.pyendpoint.port) diff --git a/src/cutecoin/core/net/network.py b/src/cutecoin/core/net/network.py index 62b26dcf1689041346cfaf8a09f058aae2d409cf..49cc2be80c95e63a1a892a58f694efa57c2a9cd4 100644 --- a/src/cutecoin/core/net/network.py +++ b/src/cutecoin/core/net/network.py @@ -12,7 +12,8 @@ import asyncio from ucoinpy.documents.peer import Peer from ucoinpy.documents.block import Block -from .api import bma as qtbma +from ucoinpy.api import bma + from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer from collections import Counter @@ -73,7 +74,13 @@ class Network(QObject): other_node._uid = node.uid other_node._version = node.version other_node._software = node.software - if other_node.block['hash'] != node.block['hash']: + switch = False + if other_node.block and node.block: + if other_node.block['hash'] != node.block['hash']: + switch = True + else: + switch = True + if switch: other_node.set_block(node.block) other_node.last_change = node.last_change other_node.state = node.state @@ -165,8 +172,7 @@ class Network(QObject): Get the latest block considered valid It is the most frequent last block of every known nodes """ - blocks_numbers = [n.block['number'] for n in self.synced_nodes - if n.block != qtbma.blockchain.Block.null_value] + blocks_numbers = [n.block['number'] for n in self.synced_nodes if n.block] if len(blocks_numbers) > 0: return blocks_numbers[0] else: @@ -178,8 +184,7 @@ class Network(QObject): Get the latest block considered valid It is the most frequent last block of every known nodes """ - blocks_hash = [n.block['hash'] for n in self.synced_nodes - if n.block != qtbma.blockchain.Block.null_value] + blocks_hash = [n.block['hash'] for n in self.synced_nodes if n.block] if len(blocks_hash) > 0: return blocks_hash[0] else: @@ -194,7 +199,7 @@ class Network(QObject): 4 : The biggest number or timestamp """ # rule number 1 : block of the majority - blocks = [n.block['hash'] for n in self.nodes if n.block != qtbma.blockchain.Block.null_value] + blocks = [n.block['hash'] for n in self.nodes if n.block] blocks_occurences = Counter(blocks) blocks_by_occurences = {} for key, value in blocks_occurences.items(): diff --git a/src/cutecoin/core/net/node.py b/src/cutecoin/core/net/node.py index 794f40ffd13b5cd8710752c52316e1f0204e8f47..d90f29a280b1b6cc3d0b3a4d8f5e7aac1fb69367 100644 --- a/src/cutecoin/core/net/node.py +++ b/src/cutecoin/core/net/node.py @@ -4,12 +4,12 @@ Created on 21 févr. 2015 @author: inso """ -from ucoinpy.documents.peer import Peer +from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint from ucoinpy.documents.block import Block from ...tools.exceptions import InvalidNodeCurrency -from ..net.api import bma as qtbma -from ..net.endpoint import Endpoint, BMAEndpoint -from ..net.api.bma import ConnectionHandler +from ...tools.decorators import asyncify +from ucoinpy.api import bma as bma +from ucoinpy.api.bma import ConnectionHandler import asyncio import logging @@ -69,37 +69,21 @@ class Node(QObject): :param str address: The node address :param int port: The node port """ - def handle_reply(reply): - if reply.error() == QNetworkReply.NoError: - strdata = bytes(reply.readAll()).decode('utf-8') - nonlocal peer_data - peer_data = json.loads(strdata) - future_reply.set_result(True) - else: - future_reply.set_result(False) - - future_reply = asyncio.Future() - peer_data = {} - reply = qtbma.network.Peering(ConnectionHandler(network_manager, address, port)).get() - reply.finished.connect(lambda: handle_reply(reply)) - - yield from future_reply - if future_reply.result(): - peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'], - peer_data['signature'])) - - if currency is not None: - if peer.currency != currency: - raise InvalidNodeCurrency(peer.currency, currency) - - node = cls(network_manager, peer.currency, - [Endpoint.from_inline(e.inline()) for e in peer.endpoints], - "", peer.pubkey, qtbma.blockchain.Block.null_value, Node.ONLINE, time.time(), - {'root': "", 'leaves': []}, "", "", 0) - logging.debug("Node from address : {:}".format(str(node))) - return node - else: - return None + peer_data = yield from bma.network.Peering(ConnectionHandler(address, port)).get() + + peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'], + peer_data['signature'])) + + if currency is not None: + if peer.currency != currency: + raise InvalidNodeCurrency(peer.currency, currency) + + node = cls(network_manager, peer.currency, + [Endpoint.from_inline(e.inline()) for e in peer.endpoints], + "", peer.pubkey, None, Node.ONLINE, time.time(), + {'root': "", 'leaves': []}, "", "", 0) + logging.debug("Node from address : {:}".format(str(node))) + return node @classmethod def from_peer(cls, network_manager, currency, peer, pubkey): @@ -114,9 +98,8 @@ class Node(QObject): if peer.currency != currency: raise InvalidNodeCurrency(peer.currency, currency) - node = cls(network_manager, peer.currency, - [Endpoint.from_inline(e.inline()) for e in peer.endpoints], - "", pubkey, qtbma.blockchain.Block.null_value, + node = cls(network_manager, peer.currency, peer.endpoints, + "", pubkey, bma.blockchain.Block.null_value, Node.ONLINE, time.time(), {'root': "", 'leaves': []}, "", "", 0) @@ -131,7 +114,7 @@ class Node(QObject): software = "" version = "" fork_window = 0 - block = qtbma.blockchain.Block.null_value + block = None last_change = time.time() state = Node.ONLINE logging.debug(data) @@ -303,50 +286,37 @@ class Node(QObject): logging.debug("Refresh summary") self.refresh_summary() + @asyncify + @asyncio.coroutine def refresh_block(self): - conn_handler = self.endpoint.conn_handler(self.network_manager) + conn_handler = self.endpoint.conn_handler() logging.debug("Requesting {0}".format(conn_handler)) - reply = qtbma.blockchain.Current(conn_handler).get() - reply.finished.connect(self.handle_block_reply) - - @pyqtSlot() - def handle_block_reply(self): - reply = self.sender() - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - - if self.check_noerror(reply.error(), status_code): - if status_code == 200: - strdata = bytes(reply.readAll()).decode('utf-8') - block_data = json.loads(strdata) - block_hash = block_data['hash'] - elif status_code == 404: - self.set_block(qtbma.blockchain.Block.null_value) + try: + block_data = yield from bma.blockchain.Current(conn_handler).get() + block_hash = block_data['hash'] if block_hash != self.block['hash']: self.set_block(block_data) logging.debug("Changed block {0} -> {1}".format(self.block['number'], block_data['number'])) self.changed.emit() - - else: + except ValueError as e: + if '404' in e: + self.set_block(None) logging.debug("Error in block reply") self.changed.emit() + except asyncio.TimeoutError: + logging.debug("Timeout error : {0}".format(self.pubkey)) + self.state = Node.OFFLINE + @asyncify + @asyncio.coroutine def refresh_informations(self): - conn_handler = self.endpoint.conn_handler(self.network_manager) - - peering_reply = qtbma.network.Peering(conn_handler).get() - peering_reply.finished.connect(self.handle_peering_reply) - - @pyqtSlot() - def handle_peering_reply(self): - reply = self.sender() - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) + conn_handler = self.endpoint.conn_handler() - if self.check_noerror(reply.error(), status_code): - strdata = bytes(reply.readAll()).decode('utf-8') - peering_data = json.loads(strdata) + try: + peering_data = yield from bma.network.Peering(conn_handler).get() logging.debug(peering_data) node_pubkey = peering_data["pubkey"] node_currency = peering_data["currency"] @@ -363,114 +333,89 @@ class Node(QObject): if change: self.changed.emit() - else: - logging.debug("Error in peering reply") + except ValueError as e: + logging.debug("Error in peering reply : {0}".format(str(e))) self.changed.emit() + except asyncio.TimeoutError: + logging.debug("Timeout error : {0}".format(self.pubkey)) + self.state = Node.OFFLINE def refresh_summary(self): - conn_handler = self.endpoint.conn_handler(self.network_manager) + conn_handler = self.endpoint.conn_handler() - summary_reply = qtbma.node.Summary(conn_handler).get() - summary_reply.finished.connect(self.handle_summary_reply) - - @pyqtSlot() - def handle_summary_reply(self): - reply = self.sender() - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - - if self.check_noerror(reply.error(), status_code): - strdata = bytes(reply.readAll()).decode('utf-8') - summary_data = json.loads(strdata) + try: + summary_data = yield from bma.node.Summary(conn_handler).get() self.software = summary_data["ucoin"]["software"] self.version = summary_data["ucoin"]["version"] if "forkWindowSize" in summary_data["ucoin"]: self.fork_window = summary_data["ucoin"]["forkWindowSize"] else: self.fork_window = 0 - else: + except ValueError as e: + logging.debug("Error in summary : {0}".format(e)) self.changed.emit() + except asyncio.TimeoutError: + logging.debug("Timeout error : {0}".format(self.pubkey)) + self.state = Node.OFFLINE def refresh_uid(self): - conn_handler = self.endpoint.conn_handler(self.network_manager) - uid_reply = qtbma.wot.Lookup(conn_handler, self.pubkey).get() - uid_reply.finished.connect(self.handle_uid_reply) - uid_reply.error.connect(lambda code: logging.debug("Error : {0}".format(code))) - - @pyqtSlot() - def handle_uid_reply(self): - reply = self.sender() - status_code = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute ); - - if self.check_noerror(reply.error(), status_code): - uid = '' - if status_code == 200: - strdata = bytes(reply.readAll()).decode('utf-8') - data = json.loads(strdata) - timestamp = 0 - for result in data['results']: - if result["pubkey"] == self.pubkey: - uids = result['uids'] - for uid in uids: - if uid["meta"]["timestamp"] > timestamp: - timestamp = uid["meta"]["timestamp"] - uid = uid["uid"] - elif status_code == 404: - logging.debug("UID not found") + conn_handler = self.endpoint.conn_handler() + try: + data = yield from bma.wot.Lookup(conn_handler, self.pubkey).get() + timestamp = 0 + for result in data['results']: + if result["pubkey"] == self.pubkey: + uids = result['uids'] + for uid in uids: + if uid["meta"]["timestamp"] > timestamp: + timestamp = uid["meta"]["timestamp"] + uid = uid["uid"] if self._uid != uid: self._uid = uid self.changed.emit() - else: - logging.debug("error in uid reply") - self.changed.emit() + except ValueError as e: + if '404' in str(e): + logging.debug("UID not found") + else: + logging.debug("error in uid reply") + self.changed.emit() + except asyncio.TimeoutError: + logging.debug("Timeout error : {0}".format(self.pubkey)) + self.state = Node.OFFLINE def refresh_peers(self): - conn_handler = self.endpoint.conn_handler(self.network_manager) - - reply = qtbma.network.peering.Peers(conn_handler).get(leaves='true') - reply.finished.connect(self.handle_peers_reply) - reply.error.connect(lambda code: logging.debug("Error : {0}".format(code))) - - @pyqtSlot() - def handle_peers_reply(self): - reply = self.sender() - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) + conn_handler = self.endpoint.conn_handler() - if self.check_noerror(reply.error(), status_code): - strdata = bytes(reply.readAll()).decode('utf-8') - peers_data = json.loads(strdata) + try: + peers_data = yield from bma.network.peering.Peers(conn_handler).get(leaves='true') if peers_data['root'] != self._last_merkle['root']: leaves = [leaf for leaf in peers_data['leaves'] if leaf not in self._last_merkle['leaves']] for leaf_hash in leaves: - conn_handler = self.endpoint.conn_handler(self.network_manager) - leaf_reply = qtbma.network.peering.Peers(conn_handler).get(leaf=leaf_hash) - leaf_reply.finished.connect(self.handle_leaf_reply) + try: + leaf_data = yield from bma.network.peering.Peers(conn_handler).get(leaf=leaf_hash) + if "raw" in leaf_data['leaf']['value']: + peer_doc = Peer.from_signed_raw("{0}{1}\n".format(leaf_data['leaf']['value']['raw'], + leaf_data['leaf']['value']['signature'])) + pubkey = leaf_data['leaf']['value']['pubkey'] + self.neighbour_found.emit(peer_doc, pubkey) + else: + logging.debug("Incorrect leaf reply") + except ValueError as e: + logging.debug("Error in leaf reply") + self.changed.emit() self._last_merkle = {'root' : peers_data['root'], 'leaves': peers_data['leaves']} - else: + except ValueError as e: logging.debug("Error in peers reply") self.changed.emit() - - @pyqtSlot() - def handle_leaf_reply(self): - reply = self.sender() - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - - if self.check_noerror(reply.error(), status_code): - strdata = bytes(reply.readAll()).decode('utf-8') - leaf_data = json.loads(strdata) - if "raw" in leaf_data['leaf']['value']: - peer_doc = Peer.from_signed_raw("{0}{1}\n".format(leaf_data['leaf']['value']['raw'], - leaf_data['leaf']['value']['signature'])) - pubkey = leaf_data['leaf']['value']['pubkey'] - self.neighbour_found.emit(peer_doc, pubkey) - else: - logging.debug("Incorrect leaf reply") - else: - logging.debug("Error in leaf reply") - self.changed.emit() + except asyncio.TimeoutError: + logging.debug("Timeout error : {0}".format(self.pubkey)) + self.state = Node.OFFLINE def __str__(self): - return ','.join([str(self.pubkey), str(self.endpoint.server), str(self.endpoint.ipv4), str(self.endpoint.port), str(self.block['number']), + return ','.join([str(self.pubkey), str(self.endpoint.server), + str(self.endpoint.ipv4), str(self.endpoint.port), + str(self.block['number'] if self.block else "None"), str(self.currency), str(self.state), str(self.neighbours)]) diff --git a/src/cutecoin/core/registry/identities.py b/src/cutecoin/core/registry/identities.py index eea2f3d778697ee7dde857170215c25b1dee3072..0d85d1dbea78ff6a3600144adf4eff88a038096f 100644 --- a/src/cutecoin/core/registry/identities.py +++ b/src/cutecoin/core/registry/identities.py @@ -1,10 +1,11 @@ from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma from .identity import Identity, LocalState, BlockchainState import json import asyncio import logging +from aiohttp.errors import ClientError class IdentitiesRegistry: @@ -44,74 +45,55 @@ class IdentitiesRegistry: @asyncio.coroutine def future_find(self, pubkey, community): - def handle_certifiersof_reply(reply, tries=0): - err = reply.error() - # https://github.com/ucoin-io/ucoin/issues/146 - if reply.error() == QNetworkReply.NoError \ - or reply.error() == QNetworkReply.ContentNotFoundError \ - or reply.error() == QNetworkReply.ProtocolInvalidOperationError: - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - if status_code == 200: - strdata = bytes(reply.readAll()).decode('utf-8') - data = json.loads(strdata) - - identity.uid = data['uid'] - identity.local_state = LocalState.PARTIAL - identity.blockchain_state = BlockchainState.VALIDATED - logging.debug("Lookup : found {0}".format(identity)) - if not future_identity.cancelled(): - future_identity.set_result(identity) - else: - reply = community.bma_access.simple_request(qtbma.wot.Lookup, + def lookup(): + identity = Identity.empty(pubkey) + self._instances[pubkey] = identity + lookup_tries = 0 + while lookup_tries < 3: + try: + data = yield from community.bma_access.simple_request(bma.wot.Lookup, req_args={'search': pubkey}) - reply.finished.connect(lambda: handle_lookup_reply(reply)) - elif tries < 3: - reply = community.bma_access.simple_request(qtbma.wot.CertifiersOf, req_args={'search': pubkey}) - reply.finished.connect(lambda: handle_certifiersof_reply(reply, tries=tries+1)) - elif not future_identity.cancelled(): - future_identity.set_result(identity) - - def handle_lookup_reply(reply, tries=0): - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - if reply.error() == QNetworkReply.NoError and status_code == 200: - strdata = bytes(reply.readAll()).decode('utf-8') - data = json.loads(strdata) - - timestamp = 0 - for result in data['results']: - if result["pubkey"] == identity.pubkey: - uids = result['uids'] - identity_uid = "" - for uid_data in uids: - if uid_data["meta"]["timestamp"] > timestamp: - timestamp = uid_data["meta"]["timestamp"] - identity_uid = uid_data["uid"] - identity.uid = identity_uid - identity.blockchain_state = BlockchainState.BUFFERED - identity.local_state = LocalState.PARTIAL - logging.debug("Lookup : found {0}".format(identity)) - if not future_identity.cancelled(): - future_identity.set_result(identity) - return - if not future_identity.cancelled(): - future_identity.set_result(identity) - elif tries < 3: - reply = community.bma_access.simple_request(qtbma.wot.Lookup, req_args={'search': pubkey}) - reply.finished.connect(lambda: handle_lookup_reply(reply, tries=tries+1)) - elif not future_identity.cancelled(): - future_identity.set_result(identity) + timestamp = 0 + for result in data['results']: + if result["pubkey"] == identity.pubkey: + uids = result['uids'] + identity_uid = "" + for uid_data in uids: + if uid_data["meta"]["timestamp"] > timestamp: + timestamp = uid_data["meta"]["timestamp"] + identity_uid = uid_data["uid"] + identity.uid = identity_uid + identity.blockchain_state = BlockchainState.BUFFERED + identity.local_state = LocalState.PARTIAL + logging.debug("Lookup : found {0}".format(identity)) + return identity + except ValueError as e: + lookup_tries += 1 + except ClientError: + lookup_tries += 1 + return identity - future_identity = asyncio.Future() if pubkey in self._instances: identity = self._instances[pubkey] - if not future_identity.cancelled(): - future_identity.set_result(identity) else: identity = Identity.empty(pubkey) self._instances[pubkey] = identity - reply = community.bma_access.simple_request(qtbma.wot.CertifiersOf, req_args={'search': pubkey}) - reply.finished.connect(lambda: handle_certifiersof_reply(reply)) - return future_identity + tries = 0 + while tries < 3: + try: + data = yield from community.bma_access.simple_request(bma.wot.CertifiersOf, req_args={'search': pubkey}) + identity.uid = data['uid'] + identity.local_state = LocalState.PARTIAL + identity.blockchain_state = BlockchainState.VALIDATED + return identity + except ValueError as e: + if '404' in str(e): + return (yield from lookup()) + else: + tries += 1 + except ClientError: + tries += 1 + return identity def from_handled_data(self, uid, pubkey, blockchain_state): """ diff --git a/src/cutecoin/core/registry/identity.py b/src/cutecoin/core/registry/identity.py index fb65737c7cf07982ea385fe2968737ab47dc5c5b..8dedf2ade472fb3832f0e9720689d1a3722cf953 100644 --- a/src/cutecoin/core/registry/identity.py +++ b/src/cutecoin/core/registry/identity.py @@ -10,10 +10,11 @@ import asyncio from enum import Enum from ucoinpy.documents.certification import SelfCertification +from ucoinpy.api import bma as bma +from ucoinpy.api.bma import PROTOCOL_VERSION + from ...tools.exceptions import Error, NoPeerAvailable,\ MembershipNotFoundError -from ..net.api import bma as qtbma -from ..net.api.bma import PROTOCOL_VERSION from PyQt5.QtCore import QObject, pyqtSignal @@ -97,7 +98,7 @@ class Identity(QObject): :rtype: ucoinpy.documents.certification.SelfCertification """ timestamp = 0 - lookup_data = yield from community.bma_access.future_request(qtbma.wot.Lookup, req_args={'search': self.pubkey}) + lookup_data = yield from community.bma_access.future_request(bma.wot.Lookup, req_args={'search': self.pubkey}) for result in lookup_data['results']: if result["pubkey"] == self.pubkey: uids = result['uids'] @@ -124,17 +125,17 @@ class Identity(QObject): :param cutecoin.core.community.Community community: The community target to request the join date :return: A datetime object """ - search = yield from community.bma_access.future_request(qtbma.blockchain.Membership, {'search': self.pubkey}) - if search != qtbma.blockchain.Membership.null_value: + try: + search = yield from community.bma_access.future_request(bma.blockchain.Membership, + {'search': self.pubkey}) if len(search['memberships']) > 0: membership_data = search['memberships'][0] - block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': membership_data['blockNumber']}) - if block != qtbma.blockchain.Block.null_value: - return block['medianTime'] - return None - else: - raise MembershipNotFoundError(self.pubkey, community.name) + return block['medianTime'] + except ValueError as e: + if '404' in str(e) or '400' in str(e): + raise MembershipNotFoundError(self.pubkey, community.name) @asyncio.coroutine def get_expiration_date(self, community): @@ -142,18 +143,17 @@ class Identity(QObject): membership = yield from self.membership(community) join_block_number = membership['blockNumber'] try: - join_block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + join_block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': join_block_number}) - parameters = yield from community.bma_access.future_request(qtbma.blockchain.Parameters) - if join_block != qtbma.blockchain.Block.null_value \ - and parameters != qtbma.blockchain.Parameters.null_value: - join_date = join_block['medianTime'] - expiration_date = join_date + parameters['sigValidity'] - else: - return None + parameters = yield from community.bma_access.future_request(bma.blockchain.Parameters) + join_date = join_block['medianTime'] + expiration_date = join_date + parameters['sigValidity'] except NoPeerAvailable: expiration_date = None + except ValueError as e: + logging.debug("Expiration date not found") + expiration_date = None except MembershipNotFoundError: expiration_date = None return expiration_date @@ -168,9 +168,9 @@ class Identity(QObject): :param cutecoin.core.community.Community community: The community target to request the join date :return: The membership data in BMA json format """ - search = yield from community.bma_access.future_request(qtbma.blockchain.Membership, + try: + search = yield from community.bma_access.future_request(bma.blockchain.Membership, {'search': self.pubkey}) - if search != qtbma.blockchain.Membership.null_value: block_number = -1 for ms in search['memberships']: if ms['blockNumber'] > block_number: @@ -181,26 +181,29 @@ class Identity(QObject): else: membership_data = ms return membership_data - else: - raise MembershipNotFoundError(self.pubkey, community.name) + except ValueError as e: + if '404' in str(e) or '400' in str(e): + raise MembershipNotFoundError(self.pubkey, community.name) @asyncio.coroutine def published_uid(self, community): - data = yield from community.bma_access.future_request(qtbma.wot.Lookup, + try: + data = yield from community.bma_access.future_request(bma.wot.Lookup, req_args={'search': self.pubkey}) - if data != qtbma.wot.Lookup.null_value: - timestamp = 0 - - for result in data['results']: - if result["pubkey"] == self.pubkey: - uids = result['uids'] - person_uid = "" - for uid_data in uids: - if uid_data["meta"]["timestamp"] > timestamp: - timestamp = uid_data["meta"]["timestamp"] - person_uid = uid_data["uid"] - if person_uid == self.uid: - return True + except ValueError as e: + if '404' in str(e): + timestamp = 0 + + for result in data['results']: + if result["pubkey"] == self.pubkey: + uids = result['uids'] + person_uid = "" + for uid_data in uids: + if uid_data["meta"]["timestamp"] > timestamp: + timestamp = uid_data["meta"]["timestamp"] + person_uid = uid_data["uid"] + if person_uid == self.uid: + return True return False @asyncio.coroutine @@ -211,9 +214,15 @@ class Identity(QObject): :param cutecoin.core.community.Community community: The community target to request the join date :return: True if the person is a member of a community """ - certifiers = yield from community.bma_access.future_request(qtbma.wot.CertifiersOf, {'search': self.pubkey}) - if certifiers != qtbma.wot.CertifiersOf.null_value: + try: + certifiers = yield from community.bma_access.future_request(bma.wot.CertifiersOf, + {'search': self.pubkey}) return certifiers['isMember'] + except ValueError as e: + if '404' in str(e): + pass + else: + raise return False @asyncio.coroutine @@ -225,33 +234,10 @@ class Identity(QObject): :param cutecoin.core.community.Community community: The community target to request the join date :return: The list of the certifiers of this community """ - data = yield from community.bma_access.future_request(qtbma.wot.CertifiersOf, {'search': self.pubkey}) - certifiers = list() + try: + data = yield from community.bma_access.future_request(bma.wot.CertifiersOf, {'search': self.pubkey}) - if data == qtbma.wot.CertifiersOf.null_value: - logging.debug('bma.wot.CertifiersOf request error') - data = yield from community.bma_access.future_request(qtbma.wot.Lookup, {'search': self.pubkey}) - if data == qtbma.wot.Lookup.null_value: - logging.debug('bma.wot.Lookup request error') - else: - for result in data['results']: - if result["pubkey"] == self.pubkey: - for uid_data in result['uids']: - for certifier_data in uid_data['others']: - for uid in certifier_data['uids']: - # add a certifier - certifier = {} - certifier['identity'] = identities_registry.from_handled_data(uid, - certifier_data['pubkey'], - BlockchainState.BUFFERED) - block = yield from community.bma_access.future_request(qtbma.blockchain.Block, - {'number': certifier_data['meta']['block_number']}) - certifier['cert_time'] = block['medianTime'] - certifier['block_number'] = None - - certifiers.append(certifier) - else: for certifier_data in data['certifications']: certifier = {} certifier['identity'] = identities_registry.from_handled_data(certifier_data['uid'], @@ -260,6 +246,29 @@ class Identity(QObject): certifier['cert_time'] = certifier_data['cert_time']['medianTime'] certifier['block_number'] = certifier_data['cert_time']['block'] certifiers.append(certifier) + except ValueError as e: + if '404' in str(e): + logging.debug('bma.wot.CertifiersOf request error: {0}'.format(str(e))) + try: + data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey}) + for result in data['results']: + if result["pubkey"] == self.pubkey: + for uid_data in result['uids']: + for certifier_data in uid_data['others']: + for uid in certifier_data['uids']: + # add a certifier + certifier = {} + certifier['identity'] = identities_registry.from_handled_data(uid, + certifier_data['pubkey'], + BlockchainState.BUFFERED) + block = yield from community.bma_access.future_request(bma.blockchain.Block, + {'number': certifier_data['meta']['block_number']}) + certifier['cert_time'] = block['medianTime'] + certifier['block_number'] = None + + certifiers.append(certifier) + except ValueError as e: + logging.debug("Lookup error : {0}".format(str(e))) return certifiers @asyncio.coroutine @@ -291,25 +300,9 @@ class Identity(QObject): :param cutecoin.core.community.Community community: The community target to request the join date :return: The list of the certified persons of this community in BMA json format """ - data = yield from community.bma_access.future_request(qtbma.wot.CertifiedBy, {'search': self.pubkey}) certified_list = list() - if data == qtbma.wot.CertifiedBy.null_value: - logging.debug('bma.wot.CertifiersOf request error') - data = yield from community.bma_access.future_request(qtbma.wot.Lookup, {'search': self.pubkey}) - if data == qtbma.wot.Lookup.null_value: - logging.debug('bma.wot.Lookup request error') - else: - for result in data['results']: - if result["pubkey"] == self.pubkey: - for certified_data in result['signed']: - certified = {} - certified['identity'] = identities_registry.from_handled_data(certified_data['uid'], - certified_data['pubkey'], - BlockchainState.BUFFERED) - certified['cert_time'] = certified_data['meta']['timestamp'] - certified['block_number'] = None - certified_list.append(certified) - else: + try: + data = yield from community.bma_access.future_request(bma.wot.CertifiedBy, {'search': self.pubkey}) for certified_data in data['certifications']: certified = {} certified['identity'] = identities_registry.from_handled_data(certified_data['uid'], @@ -318,6 +311,24 @@ class Identity(QObject): certified['cert_time'] = certified_data['cert_time']['medianTime'] certified['block_number'] = certified_data['cert_time']['block'] certified_list.append(certified) + except ValueError as e: + if '404' in str(e): + logging.debug('bma.wot.CertifiersOf request error') + try: + data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey}) + for result in data['results']: + if result["pubkey"] == self.pubkey: + for certified_data in result['signed']: + certified = {} + certified['identity'] = identities_registry.from_handled_data(certified_data['uid'], + certified_data['pubkey'], + BlockchainState.BUFFERED) + certified['cert_time'] = certified_data['meta']['timestamp'] + certified['block_number'] = None + certified_list.append(certified) + except ValueError as e: + if '404' in str(e): + logging.debug('bma.wot.Lookup request error') return certified_list @asyncio.coroutine diff --git a/src/cutecoin/core/transfer.py b/src/cutecoin/core/transfer.py index f64303d7b34a8cfd2fa7fdcbf8d4a23986ecdcfb..cad27a826c4521ec245ebb5fd39128ad322e9b52 100644 --- a/src/cutecoin/core/transfer.py +++ b/src/cutecoin/core/transfer.py @@ -5,7 +5,7 @@ Created on 31 janv. 2015 """ import logging import asyncio -from .net.api import bma as qtbma +from ucoinpy.api import bma from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject from PyQt5.QtNetwork import QNetworkReply import hashlib @@ -108,36 +108,26 @@ class Transfer(QObject): :param txdoc: A transaction ucoinpy object :param community: The community target of the transaction """ - replies = community.bma_access.broadcast(qtbma.tx.Process, + try: + error = 0 + replies = yield from community.bma_access.broadcast(bma.tx.Process, post_args={'transaction': txdoc.signed_raw()}) - for r in replies: - r.finished.connect(lambda reply=r: self.__handle_transfers_reply(replies, reply)) - - self.state = Transfer.AWAITING - self.hash = hashlib.sha1(txdoc.signed_raw().encode("ascii")).hexdigest().upper() - blockid = yield from community.blockid() - block = yield from community.bma_access.future_request(qtbma.blockchain.Block, - req_args={'number': blockid['number']}) - if block != qtbma.blockchain.Block.null_value: - self._metadata['block'] = blockid['number'] - self._metadata['time'] = block['medianTime'] - - def __handle_transfers_reply(self, replies, reply): - strdata = bytes(reply.readAll()).decode('utf-8') - logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata)) - if reply.error() == QNetworkReply.NoError: - for r in replies: - try: - r.disconnect() - except TypeError as e: - if "disconnect()" in str(e): - logging.debug("Could not disconnect a reply") - self.transfer_broadcasted.emit(self.metadata['receiver_uid']) - else: - for r in replies: - if not r.isFinished() or r.error() == QNetworkReply.NoError: - return - self.broadcast_error.emit(r.error(), strdata) + self.state = Transfer.AWAITING + self.hash = hashlib.sha1(txdoc.signed_raw().encode("ascii")).hexdigest().upper() + blockid = yield from community.blockid() + block = yield from community.bma_access.future_request(bma.blockchain.Block, + req_args={'number': blockid['number']}) + if block != bma.blockchain.Block.null_value: + self._metadata['block'] = blockid['number'] + self._metadata['time'] = block['medianTime'] + except ValueError as e: + error += 1 + error_msg = str(e) + finally: + if error < len(replies): + self.transfer_broadcasted.emit(self.metadata['receiver_uid']) + else: + self.broadcast_error.emit(0, error_msg) def check_registered(self, txhash, block_number, time, data_validation): """ diff --git a/src/cutecoin/core/txhistory.py b/src/cutecoin/core/txhistory.py index 55e52e43232826171196b025e53c7982186de632..d7f2a9582ef33e2af0aa8a9829c2578238e05c96 100644 --- a/src/cutecoin/core/txhistory.py +++ b/src/cutecoin/core/txhistory.py @@ -5,7 +5,7 @@ from .transfer import Transfer from ucoinpy.documents.transaction import InputSource, OutputSource from ucoinpy.documents.block import Block from ..tools.exceptions import LookupFailureError -from .net.api import bma as qtbma +from ucoinpy.api import bma class TxHistory(): @@ -166,7 +166,7 @@ class TxHistory(): block = None tries = 0 while block is None and tries < 3: - block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': block_number}) signed_raw = "{0}{1}\n".format(block['raw'], block['signature']) @@ -191,17 +191,20 @@ class TxHistory(): @asyncio.coroutine def request_dividends(self, community, parsed_block): - dividends_data = qtbma.ud.History.null_value for i in range(0, 6): - if dividends_data == qtbma.ud.History.null_value: - dividends_data = yield from community.bma_access.future_request(qtbma.ud.History, + try: + dividends_data = yield from community.bma_access.future_request(bma.ud.History, req_args={'pubkey': self.wallet.pubkey}) - dividends = dividends_data['history']['history'] - for d in dividends: - if d['block_number'] < parsed_block: - dividends.remove(d) - return dividends + dividends = dividends_data['history']['history'] + for d in dividends: + if d['block_number'] < parsed_block: + dividends.remove(d) + return dividends + except ValueError as e: + if '404' in str(e): + pass + return {} @asyncio.coroutine def refresh(self, community, received_list): @@ -211,7 +214,7 @@ class TxHistory(): :param cutecoin.core.Community community: The community :param list received_list: List of transactions received """ - current_block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + current_block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': community.network.latest_block_number}) members_pubkeys = yield from community.members_pubkeys() # We look for the first block to parse, depending on awaiting and validating transfers and ud... @@ -223,7 +226,7 @@ class TxHistory(): parsed_block = min(set(blocks)) logging.debug("Refresh from : {0} to {1}".format(self.latest_block, current_block['number'])) dividends = yield from self.request_dividends(community, parsed_block) - with_tx_data = yield from community.bma_access.future_request(qtbma.blockchain.TX) + with_tx_data = yield from community.bma_access.future_request(bma.blockchain.TX) blocks_with_tx = with_tx_data['result']['blocks'] new_transfers = [] new_dividends = [] diff --git a/src/cutecoin/core/txhistory_indexation.py b/src/cutecoin/core/txhistory_indexation.py index 399f1f064bf7f5a385b6f156a55dae6fce5b34de..d608a0eebb981b4672f9eac905291b8ba73c5655 100644 --- a/src/cutecoin/core/txhistory_indexation.py +++ b/src/cutecoin/core/txhistory_indexation.py @@ -3,7 +3,7 @@ import logging from .transfer import Transfer from ucoinpy.documents.transaction import InputSource, OutputSource from ..tools.exceptions import LookupFailureError -from .net.api import bma as qtbma +from ucoinpy.api import bma class TxHistory(): @@ -166,7 +166,7 @@ class TxHistory(): :param cutecoin.core.Community community: The community :param list received_list: List of transactions received """ - current_block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + current_block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': community.network.latest_block_number}) members_pubkeys = yield from community.members_pubkeys() # We look for the first block to parse, depending on awaiting and validating transfers and ud... @@ -177,10 +177,10 @@ class TxHistory(): [max(0, self.latest_block - community.network.fork_window(members_pubkeys))] parsed_block = min(set(blocks)) logging.debug("Refresh from : {0} to {1}".format(self.latest_block, current_block['number'])) - dividends_data = qtbma.ud.History.null_value + dividends_data = bma.ud.History.null_value for i in range(0, 6): - if dividends_data == qtbma.ud.History.null_value: - dividends_data = yield from community.bma_access.future_request(qtbma.ud.History, + if dividends_data == bma.ud.History.null_value: + dividends_data = yield from community.bma_access.future_request(bma.ud.History, req_args={'pubkey': self.wallet.pubkey}) dividends = dividends_data['history']['history'] @@ -208,16 +208,16 @@ class TxHistory(): if ud['block_number'] == d['block_number']][0] known_dividend['state'] = state - tx_history = qtbma.tx.history.Blocks.null_value + tx_history = bma.tx.history.Blocks.null_value for i in range(0, 6): - if tx_history == qtbma.tx.history.Blocks.null_value: - tx_history = yield from community.bma_access.future_request(qtbma.tx.history.Blocks, + if tx_history == bma.tx.history.Blocks.null_value: + tx_history = yield from community.bma_access.future_request(bma.tx.history.Blocks, req_args={'pubkey': self.wallet.pubkey, 'from_':str(parsed_block), 'to_': str(parsed_block + 99)}) # If after 6 requests we still get wrong data # we continue to next loop - if tx_history == qtbma.tx.history.Blocks.null_value: + if tx_history == bma.tx.history.Blocks.null_value: continue # We parse only blocks with transactions diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index faa268b8085d264aa73ea57eec32a5cc9b1eec89..22a7bcb7aa0141c79bd39de377bd1f36f2625f9d 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -7,8 +7,8 @@ Created on 1 févr. 2014 from ucoinpy.documents.transaction import InputSource, OutputSource, Transaction from ucoinpy.key import SigningKey -from .net.api import bma as qtbma -from .net.api.bma import PROTOCOL_VERSION +from ucoinpy.api import bma +from ucoinpy.api.bma import PROTOCOL_VERSION from ..tools.exceptions import NotEnoughMoneyError, NoPeerAvailable, LookupFailureError from .transfer import Transfer from .txhistory import TxHistory @@ -220,7 +220,7 @@ class Wallet(QObject): """ blockid = yield from community.blockid() block_number = blockid['number'] - block = yield from community.bma_access.future_request(qtbma.blockchain.Block, + block = yield from community.bma_access.future_request(bma.blockchain.Block, req_args={'number': block_number}) time = block['medianTime'] txid = len(block['transactions']) @@ -284,7 +284,7 @@ class Wallet(QObject): :param cutecoin.core.community.Community community: The community where we want available sources :return: List of InputSource ucoinpy objects """ - data = yield from community.bma_access.future_request(qtbma.tx.Sources, + data = yield from community.bma_access.future_request(bma.tx.Sources, req_args={'pubkey': self.pubkey}) tx = [] for s in data['sources']: @@ -299,7 +299,7 @@ class Wallet(QObject): :param cutecoin.core.community.Community community: The community where we want available sources :return: List of InputSource ucoinpy objects """ - data = yield from community.bma_access.future_request(qtbma.tx.Sources, + data = yield from community.bma_access.future_request(bma.tx.Sources, req_args={'pubkey': self.pubkey}) tx = [] for s in data['sources']: diff --git a/src/cutecoin/gui/certification.py b/src/cutecoin/gui/certification.py index cd2baf04c42615f0f39132f7622adf2c0dd2db55..4bc18e893db1be7e43ae2fd4c91e505fac011e48 100644 --- a/src/cutecoin/gui/certification.py +++ b/src/cutecoin/gui/certification.py @@ -7,7 +7,7 @@ from PyQt5.QtWidgets import QDialog, QMessageBox, QDialogButtonBox, QApplication from PyQt5.QtCore import Qt, pyqtSlot from ..gen_resources.certification_uic import Ui_CertificationDialog from . import toast -from ..core.net.api import bma as qtbma +from ..core.net.api import bma as bma from ..tools.decorators import asyncify import asyncio import logging @@ -88,8 +88,12 @@ class CertificationDialog(QDialog, Ui_CertificationDialog): def refresh(self): account_identity = yield from self.account.identity(self.community) is_member = yield from account_identity.is_member(self.community) - block_0 = yield from self.community.get_block(0) - if is_member or block_0 == qtbma.blockchain.Block.null_value: + try: + block_0 = yield from self.community.get_block(0) + except ValueError as e: + if '404' in str(e): + block_0 = None + if is_member or not block_0: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok")) else: diff --git a/src/cutecoin/gui/community_view.py b/src/cutecoin/gui/community_view.py index 98aa8336a31989051c5a1f68fb6815bb37d6f530..7ca3c35c3e9c186971a9dbc69327b0aba5d26b3e 100644 --- a/src/cutecoin/gui/community_view.py +++ b/src/cutecoin/gui/community_view.py @@ -10,7 +10,7 @@ from PyQt5.QtWidgets import QWidget, QMessageBox, QDialog from PyQt5.QtCore import QModelIndex, pyqtSlot, QDateTime, QLocale, QEvent from PyQt5.QtGui import QIcon -from ..core.net.api import bma as qtbma +from ..core.net.api import bma as bma from .wot_tab import WotTabWidget from .identities_tab import IdentitiesTabWidget from .transactions_tab import TransactionsTabWidget @@ -193,12 +193,11 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): text = self.tr(" Block {0}").format(self.community.network.latest_block_number) block = yield from self.community.get_block(self.community.network.latest_block_number) - if block != qtbma.blockchain.Block.null_value: - text += " ( {0} )".format(QLocale.toString( - QLocale(), - QDateTime.fromTime_t(block['medianTime']), - QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat) - )) + text += " ( {0} )".format(QLocale.toString( + QLocale(), + QDateTime.fromTime_t(block['medianTime']), + QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat) + )) if self.community.network.quality > 0.66: icon = '<img src=":/icons/connected" width="12" height="12"/>' @@ -237,7 +236,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): logging.debug("Not a member") self.button_membership.setText(self.tr("Send membership demand")) self.button_membership.show() - if self.community.get_block(0) != qtbma.blockchain.Block.null_value: + if self.community.get_block(0) != bma.blockchain.Block.null_value: self.button_certification.hide() else: logging.debug("UID not published") diff --git a/src/cutecoin/gui/identities_tab.py b/src/cutecoin/gui/identities_tab.py index 41d1e60fb7e50c47829db138990125040d32e449..002da0fee903431402d8416b5917bbb0199c4db0 100644 --- a/src/cutecoin/gui/identities_tab.py +++ b/src/cutecoin/gui/identities_tab.py @@ -17,7 +17,7 @@ from .transfer import TransferMoneyDialog from .busy import Busy from .certification import CertificationDialog import asyncio -from ..core.net.api import bma as qtbma +from ucoinpy.api import bma from ..core.registry import Identity from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task @@ -182,7 +182,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): text = self.edit_textsearch.text() if len(text) < 2: return - response = yield from self.community.bma_access.future_request(qtbma.wot.Lookup, {'search': text}) + response = yield from self.community.bma_access.future_request(bma.wot.Lookup, {'search': text}) identities = [] for identity_data in response['results']: identity = yield from self.app.identities_registry.future_find(identity_data['pubkey'], self.community) diff --git a/src/cutecoin/gui/network_tab.py b/src/cutecoin/gui/network_tab.py index 44dfea169ae55a6883cbed141f97276827d496a4..a1dce6c3f7994ba656f61f88e21c2ad5a7fb13ca 100644 --- a/src/cutecoin/gui/network_tab.py +++ b/src/cutecoin/gui/network_tab.py @@ -11,7 +11,7 @@ from PyQt5.QtGui import QCursor, QDesktopServices from PyQt5.QtWidgets import QWidget, QMenu, QAction from PyQt5.QtCore import Qt, QModelIndex, pyqtSlot, QUrl, QEvent from ..models.network import NetworkTableModel, NetworkFilterProxyModel -from ..core.net.api import bma as qtbma +from ..core.net.api import bma as bma from ..gen_resources.network_tab_uic import Ui_NetworkTabWidget @@ -98,7 +98,7 @@ class NetworkTabWidget(QWidget, Ui_NetworkTabWidget): @pyqtSlot() def open_node_in_browser(self): node = self.sender().data() - peering = qtbma.network.Peering(node.endpoint) + peering = bma.network.Peering(node.endpoint) url = QUrl(peering.reverse_url("/peering")) QDesktopServices.openUrl(url) diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index 0b28e07e7ba6c702065107ebf1e7dbf9edbf0f3b..83f5d8a0cb934a8f507a6f26689e8786035bf0f4 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -7,7 +7,7 @@ from PyQt5.QtCore import pyqtSlot, QEvent, QLocale, QDateTime, pyqtSignal from ..tools.exceptions import MembershipNotFoundError from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task -from ..core.net.api import bma +from ucoinpy.api import bma from ..core.graph import Graph from ..core.registry import BlockchainState from .member import MemberDialog diff --git a/src/cutecoin/models/identities.py b/src/cutecoin/models/identities.py index c47717eaf6fc7498866910836c59129bf358feab..b412c455f31c4e90010283136ad265ae5086d5bf 100644 --- a/src/cutecoin/models/identities.py +++ b/src/cutecoin/models/identities.py @@ -4,7 +4,7 @@ Created on 5 févr. 2014 @author: inso """ -from ..core.net.api import bma as qtbma +from ..core.net.api import bma as bma from ..tools.exceptions import NoPeerAvailable, MembershipNotFoundError from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task from PyQt5.QtCore import QAbstractTableModel, QSortFilterProxyModel, Qt, \ diff --git a/src/cutecoin/tests/core/txhistory/test_txhistory_loading.py b/src/cutecoin/tests/core/txhistory/test_txhistory_loading.py index 26e38fa3d3cb43c40f140984a069cc15ec1d94e9..94145436a5fb13094a6658cbfbf0493b95ec6b88 100644 --- a/src/cutecoin/tests/core/txhistory/test_txhistory_loading.py +++ b/src/cutecoin/tests/core/txhistory/test_txhistory_loading.py @@ -13,10 +13,9 @@ from cutecoin.core.registry.identities import IdentitiesRegistry from cutecoin.core.app import Application from cutecoin.core import Account, Community, Wallet from cutecoin.core.net import Network, Node -from cutecoin.core.net.endpoint import BMAEndpoint from cutecoin.core.net.api.bma.access import BmaAccess from cutecoin.tests import get_application -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.documents.peer import BMAEndpoint class TestTxHistory(unittest.TestCase): diff --git a/src/cutecoin/tests/gui/certification/test_certification.py b/src/cutecoin/tests/gui/certification/test_certification.py index 71c634b046050d18fdf4a71ca4bd7e91843aaa43..b16e784b05bb46700958922e7b2099b2b277d0b0 100644 --- a/src/cutecoin/tests/gui/certification/test_certification.py +++ b/src/cutecoin/tests/gui/certification/test_certification.py @@ -4,10 +4,12 @@ import asyncio import quamash import time import logging -from ucoinpy.documents.peer import BMAEndpoint as PyBMAEndpoint +from ucoinpy.documents.peer import BMAEndpoint from PyQt5.QtWidgets import QDialog, QDialogButtonBox from PyQt5.QtCore import QLocale, Qt from PyQt5.QtTest import QTest +from ucoinpy.api.bma import API +from cutecoin.tests.mocks.monkeypatch import pretender_reversed from cutecoin.tests.mocks.bma import init_new_community from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager from cutecoin.core.registry.identities import IdentitiesRegistry @@ -16,10 +18,9 @@ from cutecoin.gui.password_asker import PasswordAskerDialog from cutecoin.core.app import Application from cutecoin.core import Account, Community, Wallet from cutecoin.core.net import Network, Node -from cutecoin.core.net.endpoint import BMAEndpoint from cutecoin.core.net.api.bma.access import BmaAccess from cutecoin.tests import get_application -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma class TestCertificationDialog(unittest.TestCase): @@ -34,10 +35,10 @@ class TestCertificationDialog(unittest.TestCase): self.application = Application(self.qapplication, self.lp, self.network_manager, self.identities_registry) self.application.preferences['notifications'] = False - self.endpoint = BMAEndpoint(PyBMAEndpoint("", "127.0.0.1", "", 50000)) + self.endpoint = BMAEndpoint("", "127.0.0.1", "", 50000) self.node = Node(self.network_manager, "test_currency", [self.endpoint], "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - qtbma.blockchain.Block.null_value, Node.ONLINE, + None, Node.ONLINE, time.time(), {}, "ucoin", "0.14.0", 0) self.network = Network.create(self.network_manager, self.node) self.bma_access = BmaAccess.create(self.network) @@ -66,6 +67,7 @@ class TestCertificationDialog(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) certification_dialog = CertificationDialog(self.application, self.account, self.password_asker) diff --git a/src/cutecoin/tests/gui/identities_tab/test_identities_table.py b/src/cutecoin/tests/gui/identities_tab/test_identities_table.py index 83e54e923d69619a75c5f6dbe27785a61e386160..7e9ae2ab117ded171db241ee77b487696c9f1522 100644 --- a/src/cutecoin/tests/gui/identities_tab/test_identities_table.py +++ b/src/cutecoin/tests/gui/identities_tab/test_identities_table.py @@ -8,7 +8,9 @@ from ucoinpy.documents.peer import BMAEndpoint as PyBMAEndpoint from PyQt5.QtWidgets import QDialog from PyQt5.QtCore import QLocale, Qt, QPoint from PyQt5.QtTest import QTest -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma +from ucoinpy.api.bma import API +from cutecoin.tests.mocks.monkeypatch import pretender_reversed from cutecoin.tests.mocks.bma import nice_blockchain from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager from cutecoin.core.registry.identities import IdentitiesRegistry @@ -17,7 +19,7 @@ from cutecoin.gui.password_asker import PasswordAskerDialog from cutecoin.core.app import Application from cutecoin.core import Account, Community, Wallet from cutecoin.core.net import Network, Node -from cutecoin.core.net.endpoint import BMAEndpoint +from ucoinpy.documents.peer import BMAEndpoint from cutecoin.core.net.api.bma.access import BmaAccess from cutecoin.tests import get_application @@ -34,10 +36,10 @@ class TestIdentitiesTable(unittest.TestCase): self.application = Application(self.qapplication, self.lp, self.network_manager, self.identities_registry) self.application.preferences['notifications'] = False - self.endpoint = BMAEndpoint(PyBMAEndpoint("", "127.0.0.1", "", 50000)) + self.endpoint = BMAEndpoint("", "127.0.0.1", "", 50000) self.node = Node(self.network_manager, "test_currency", [self.endpoint], "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - qtbma.blockchain.Block.null_value, Node.ONLINE, + None, Node.ONLINE, time.time(), {}, "ucoin", "0.14.0", 0) self.network = Network.create(self.network_manager, self.node) self.bma_access = BmaAccess.create(self.network) @@ -66,6 +68,7 @@ class TestIdentitiesTable(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) identities_tab = IdentitiesTabWidget(self.application) identities_tab.change_account(self.account, self.password_asker) identities_tab.change_community(self.community) diff --git a/src/cutecoin/tests/gui/process_cfg_community/test_add_community.py b/src/cutecoin/tests/gui/process_cfg_community/test_add_community.py index dfb224a1995140fbaaedcae1dcd627429fcc674e..784028a773114f9536f487180b8b91a71473231e 100644 --- a/src/cutecoin/tests/gui/process_cfg_community/test_add_community.py +++ b/src/cutecoin/tests/gui/process_cfg_community/test_add_community.py @@ -7,6 +7,8 @@ import time from PyQt5.QtWidgets import QDialog from PyQt5.QtCore import QLocale, Qt from PyQt5.QtTest import QTest +from ucoinpy.api.bma import API +from cutecoin.tests.mocks.monkeypatch import pretender_reversed from cutecoin.tests.mocks.bma import new_blockchain, nice_blockchain from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager from cutecoin.core.registry.identities import IdentitiesRegistry @@ -47,6 +49,7 @@ class ProcessAddCommunity(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) process_community = ProcessConfigureCommunity(self.application, self.account, None, self.password_asker) @@ -104,6 +107,7 @@ class ProcessAddCommunity(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) process_community = ProcessConfigureCommunity(self.application, self.account, None, self.password_asker) @@ -156,6 +160,7 @@ class ProcessAddCommunity(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) process_community = ProcessConfigureCommunity(self.application, self.account, None, self.password_asker) diff --git a/src/cutecoin/tests/gui/transfer/test_transfer.py b/src/cutecoin/tests/gui/transfer/test_transfer.py index 55452ccbbfe274193e90aa4d4b533674edb2a44e..ab3e32b9eee3b4078dc281fd56b42161c0c0da60 100644 --- a/src/cutecoin/tests/gui/transfer/test_transfer.py +++ b/src/cutecoin/tests/gui/transfer/test_transfer.py @@ -8,6 +8,8 @@ from ucoinpy.documents.peer import BMAEndpoint as PyBMAEndpoint from PyQt5.QtWidgets import QDialog, QDialogButtonBox from PyQt5.QtCore import QLocale, Qt from PyQt5.QtTest import QTest +from ucoinpy.api.bma import API +from cutecoin.tests.mocks.monkeypatch import pretender_reversed from cutecoin.tests.mocks.bma import nice_blockchain from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager from cutecoin.core.registry.identities import IdentitiesRegistry @@ -16,10 +18,10 @@ from cutecoin.gui.password_asker import PasswordAskerDialog from cutecoin.core.app import Application from cutecoin.core import Account, Community, Wallet from cutecoin.core.net import Network, Node -from cutecoin.core.net.endpoint import BMAEndpoint +from ucoinpy.documents.peer import BMAEndpoint from cutecoin.core.net.api.bma.access import BmaAccess from cutecoin.tests import get_application -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma class TestTransferDialog(unittest.TestCase): @@ -34,10 +36,10 @@ class TestTransferDialog(unittest.TestCase): self.application = Application(self.qapplication, self.lp, self.network_manager, self.identities_registry) self.application.preferences['notifications'] = False - self.endpoint = BMAEndpoint(PyBMAEndpoint("", "127.0.0.1", "", 50000)) + self.endpoint = BMAEndpoint("", "127.0.0.1", "", 50000) self.node = Node(self.network_manager, "test_currency", [self.endpoint], "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - qtbma.blockchain.Block.null_value, Node.ONLINE, + bma.blockchain.Block.null_value, Node.ONLINE, time.time(), {}, "ucoin", "0.14.0", 0) self.network = Network.create(self.network_manager, self.node) self.bma_access = BmaAccess.create(self.network) @@ -66,6 +68,7 @@ class TestTransferDialog(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) transfer_dialog = TransferMoneyDialog(self.application, self.account, self.password_asker) diff --git a/src/cutecoin/tests/gui/wot_tab/test_wot_tab.py b/src/cutecoin/tests/gui/wot_tab/test_wot_tab.py index ce6584278c161b0e5e7e208d5a020142682961ee..8b6240faa0fa50e3c273eea2f75fd63de13b44b4 100644 --- a/src/cutecoin/tests/gui/wot_tab/test_wot_tab.py +++ b/src/cutecoin/tests/gui/wot_tab/test_wot_tab.py @@ -4,11 +4,13 @@ import asyncio import quamash import logging import time -from ucoinpy.documents.peer import BMAEndpoint as PyBMAEndpoint +from ucoinpy.documents.peer import BMAEndpoint from PyQt5.QtWidgets import QDialog from PyQt5.QtCore import QLocale, Qt from PyQt5.QtTest import QTest -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma +from ucoinpy.api.bma import API +from cutecoin.tests.mocks.monkeypatch import pretender_reversed from cutecoin.tests.mocks.bma import nice_blockchain from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager from cutecoin.core.registry.identities import IdentitiesRegistry @@ -17,7 +19,6 @@ from cutecoin.gui.password_asker import PasswordAskerDialog from cutecoin.core.app import Application from cutecoin.core import Account, Community, Wallet from cutecoin.core.net import Network, Node -from cutecoin.core.net.endpoint import BMAEndpoint from cutecoin.core.net.api.bma.access import BmaAccess from cutecoin.tests import get_application @@ -34,10 +35,10 @@ class TestIdentitiesTable(unittest.TestCase): self.application = Application(self.qapplication, self.lp, self.network_manager, self.identities_registry) self.application.preferences['notifications'] = False - self.endpoint = BMAEndpoint(PyBMAEndpoint("", "127.0.0.1", "", 50000)) + self.endpoint = BMAEndpoint("", "127.0.0.1", "", 50000) self.node = Node(self.network_manager, "test_currency", [self.endpoint], "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - qtbma.blockchain.Block.null_value, Node.ONLINE, + None, Node.ONLINE, time.time(), {}, "ucoin", "0.14.0", 0) self.network = Network.create(self.network_manager, self.node) self.bma_access = BmaAccess.create(self.network) @@ -66,6 +67,7 @@ class TestIdentitiesTable(unittest.TestCase): time.sleep(2) logging.debug(mock.pretend_url) self.network_manager.set_mock_path(mock.pretend_url) + API.reverse_url = pretender_reversed(mock.pretend_url) wot_tab = WotTabWidget(self.application) future = asyncio.Future() diff --git a/src/cutecoin/tests/mocks/monkeypatch.py b/src/cutecoin/tests/mocks/monkeypatch.py new file mode 100644 index 0000000000000000000000000000000000000000..7df5878d5afe777a1b88e2924eb8a5508d984ca3 --- /dev/null +++ b/src/cutecoin/tests/mocks/monkeypatch.py @@ -0,0 +1,16 @@ + + +def pretender_reversed(pretender_id): + def reverse_url(inst, path): + """ + Reverses the url using self.url and path given in parameter. + + Arguments: + - `path`: the request path + """ + + server, port = inst.connection_handler.server, inst.connection_handler.port + + url = '%s/%s' % (pretender_id, inst.module) + return url + path + return reverse_url \ No newline at end of file diff --git a/src/cutecoin/tests/stubs/core/registry/identities.py b/src/cutecoin/tests/stubs/core/registry/identities.py index 7cebf6522df4f7b40d3496c3578eaa60dc7c18b7..1a2a90dd30fad8327cba72457bc27e3626e453d6 100644 --- a/src/cutecoin/tests/stubs/core/registry/identities.py +++ b/src/cutecoin/tests/stubs/core/registry/identities.py @@ -1,5 +1,5 @@ from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QTimer -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma from .identity import Identity import asyncio diff --git a/src/cutecoin/tests/stubs/core/registry/identity.py b/src/cutecoin/tests/stubs/core/registry/identity.py index 7c0e3a5c4b796facded48ce0e372bb3ed24341b8..a6da4340d96552170532cf7b52fd356997e6a87f 100644 --- a/src/cutecoin/tests/stubs/core/registry/identity.py +++ b/src/cutecoin/tests/stubs/core/registry/identity.py @@ -11,7 +11,7 @@ import asyncio from ucoinpy.documents.certification import SelfCertification from cutecoin.tools.exceptions import Error, NoPeerAvailable,\ MembershipNotFoundError -from cutecoin.core.net.api import bma as qtbma +from ucoinpy.api import bma from cutecoin.core.net.api.bma import PROTOCOL_VERSION from PyQt5.QtCore import QObject, pyqtSignal