From 26fa04d861990b1b4657eb52c40152cc37e490f5 Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Tue, 2 Dec 2014 22:19:20 +0100 Subject: [PATCH] New ucoin API and library --- lib/ucoin/__init__.py | 211 ------------------ lib/ucoin/hdc/amendments/__init__.py | 66 ------ lib/ucoin/hdc/amendments/view.py | 41 ---- lib/ucoin/hdc/transactions/__init__.py | 135 ----------- lib/ucoin/hdc/transactions/sender/__init__.py | 80 ------- lib/ucoin/network/__init__.py | 72 ------ lib/ucoin/network/peering/peers.py | 77 ------- lib/ucoin/pks/__init__.py | 60 ----- lib/ucoin/registry/__init__.py | 41 ---- lib/ucoin/registry/amendment/__init__.py | 37 --- lib/ucoin/registry/community/__init__.py | 54 ----- lib/ucoin/registry/community/members.py | 60 ----- lib/ucoin/registry/community/voters.py | 59 ----- lib/{ucoin/hdc => ucoinpy}/__init__.py | 12 - lib/ucoinpy/bma/__init__.py | 139 ++++++++++++ lib/ucoinpy/bma/blockchain/__init__.py | 95 ++++++++ .../coins => ucoinpy/bma/network}/__init__.py | 23 +- .../bma}/network/peering/__init__.py | 21 +- .../view.py => ucoinpy/bma/tx/__init__.py} | 30 +-- lib/ucoinpy/bma/wot/__init__.py | 51 +++++ 20 files changed, 315 insertions(+), 1049 deletions(-) delete mode 100644 lib/ucoin/__init__.py delete mode 100644 lib/ucoin/hdc/amendments/__init__.py delete mode 100644 lib/ucoin/hdc/amendments/view.py delete mode 100644 lib/ucoin/hdc/transactions/__init__.py delete mode 100644 lib/ucoin/hdc/transactions/sender/__init__.py delete mode 100644 lib/ucoin/network/__init__.py delete mode 100644 lib/ucoin/network/peering/peers.py delete mode 100644 lib/ucoin/pks/__init__.py delete mode 100644 lib/ucoin/registry/__init__.py delete mode 100644 lib/ucoin/registry/amendment/__init__.py delete mode 100644 lib/ucoin/registry/community/__init__.py delete mode 100644 lib/ucoin/registry/community/members.py delete mode 100644 lib/ucoin/registry/community/voters.py rename lib/{ucoin/hdc => ucoinpy}/__init__.py (71%) create mode 100644 lib/ucoinpy/bma/__init__.py create mode 100644 lib/ucoinpy/bma/blockchain/__init__.py rename lib/{ucoin/hdc/coins => ucoinpy/bma/network}/__init__.py (57%) rename lib/{ucoin => ucoinpy/bma}/network/peering/__init__.py (69%) rename lib/{ucoin/hdc/coins/view.py => ucoinpy/bma/tx/__init__.py} (55%) create mode 100644 lib/ucoinpy/bma/wot/__init__.py diff --git a/lib/ucoin/__init__.py b/lib/ucoin/__init__.py deleted file mode 100644 index f0d2720c..00000000 --- a/lib/ucoin/__init__.py +++ /dev/null @@ -1,211 +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 -# - -__all__ = ['api'] - -__author__ = 'uCoin team' -__version__ = '0.8.2' -__nonsense__ = 'uCoin' - -import requests -import logging -import gnupg -import json - -settings = { - 'server': 'localhost', - 'port': 8081, - 'auth': False, -} - -logger = logging.getLogger("ucoin") - - -class Response: - """Wrapper of requests.Response class in order to verify signed message.""" - - def __init__(self, response): - """ - Arguments: - - `self`: - - `response`: - """ - - self.response = response - self.status_code = response.status_code - self.headers = response.headers - - if settings.get('auth'): - self.verified, clear, self.signature = self.split_n_verify(response) - - if not self.verified: - raise ValueError('bad signature verification') - - self.text = self.clear_text = clear - self.content = self.clear_content = self.text.encode('ascii') - else: - self.text = response.text - self.content = response.content - - def json(self): - if not settings.get('auth'): - return self.response.json() - - return json.loads(self.text) - - def split_n_verify(self, response): - """ - Split the signed message thanks to the boundary - value got in content-type header. - - returns a tuple with the status, the clear message and the signature. - - `response`: the response returns by requests.get() needed - to access to headers and response content. - """ - - begin = '-----BEGIN PGP SIGNATURE-----' - end = '-----END PGP SIGNATURE-----' - boundary_pattern = 'boundary=' - - content_type = response.headers['content-type'] - boundary = content_type[content_type.index(boundary_pattern)+len(boundary_pattern):] - boundary = boundary[:boundary.index(';')].strip() - - data = [x.strip() for x in response.text.split('--%s' % boundary)] - - clear = data[1] - signed = data[2][data[2].index(begin):] - clearsigned = '-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\n%s\n%s' % (clear, signed) - - return (bool(settings['gpg'].verify(clearsigned)), clear, signed) - - -class API: - """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, module, server=None, port=None): - """ - Asks a module in order to create the url - used then by derivated classes. - - Arguments: - - `module`: module name - """ - - self.module = module - self.server = server - self.port = port - - self.headers = {} - - if settings['auth']: - self.headers['Accept'] = 'multipart/signed' - - def reverse_url(self, path): - """ - Reverses the url using self.url and path given in parameter. - - Arguments: - - `path`: the request path - """ - - url = 'http://%s:%d/%s' % (self.server if self.server - else settings['server'], - self.port if self.port - else settings['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 - """ - - response = None - - if not settings.get('auth'): - response = requests.get(self.reverse_url(path), params=kwargs, - headers=self.headers) - else: - response = Response(requests.get(self.reverse_url(path), - params=kwargs, headers=self.headers)) - - if response.status_code != 200: - raise ValueError('status code != 200 => %d (%s)' - % (response.status_code, response.text)) - - return response - - def requests_post(self, path, **kwargs): - """ - Requests POST wrapper in order to use API parameters. - - Arguments: - - `path`: the request path - """ - - response = requests.post(self.reverse_url(path), - data=kwargs, headers=self.headers) - - if response.status_code != 200: - raise ValueError('status code != 200 => %d (%s)' - % (response.status_code, 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 pks -from . import hdc -from . import network -from . import registry diff --git a/lib/ucoin/hdc/amendments/__init__.py b/lib/ucoin/hdc/amendments/__init__.py deleted file mode 100644 index eada4013..00000000 --- a/lib/ucoin/hdc/amendments/__init__.py +++ /dev/null @@ -1,66 +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 HDC -from .. import logging - -logger = logging.getLogger("ucoin/hdc/amendments") - - -class Base(HDC): - def __init__(self, server=None, port=None): - super().__init__('hdc/amendments', server, port) - - -class Promoted(Base): - """GET the current promoted amendment (amendment - which received enough votes to be accepted).""" - - def __init__(self, number=None, server=None, port=None): - """ - Uses number to fit the result. - - Arguments: - - `number`: amendment number - """ - - super().__init__(server, port) - - self.number = number - - def __get__(self, **kwargs): - if not self.number: - return self.requests_get('/promoted', **kwargs).json() - - return self.requests_get('/promoted/%d' % self.number, **kwargs).json() - - -class Votes(Base): - """GET an index of votes received by this node.""" - - def __get__(self, **kwargs): - return self.requests_get('/votes', **kwargs).json() - - def __post__(self, **kwargs): - assert 'amendment' in kwargs - assert 'signature' in kwargs - assert 'peer' in kwargs - - return self.requests_post('/votes', **kwargs).json() - -from . import view diff --git a/lib/ucoin/hdc/amendments/view.py b/lib/ucoin/hdc/amendments/view.py deleted file mode 100644 index 02a74f1e..00000000 --- a/lib/ucoin/hdc/amendments/view.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 HDC -from .. import logging - -logger = logging.getLogger("ucoin/hdc/amendments/view") - - -class View(HDC): - def __init__(self, amendment_id, server=None, port=None): - super().__init__('hdc/amendments/view/%s' % amendment_id, server, port) - - -class Self(View): - """Shows the raw data of the amendment [AMENDMENT_ID].""" - - def __get__(self, **kwargs): - return self.requests_get('/self', **kwargs).json() - - -class Signatures(View): - """GET the signatures of the Community listed in this amendment.""" - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/signatures') diff --git a/lib/ucoin/hdc/transactions/__init__.py b/lib/ucoin/hdc/transactions/__init__.py deleted file mode 100644 index 60ac2d06..00000000 --- a/lib/ucoin/hdc/transactions/__init__.py +++ /dev/null @@ -1,135 +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 HDC -from .. import logging - -logger = logging.getLogger("ucoin/hdc/transactions") - - -class Base(HDC): - def __init__(self, server=None, port=None): - super().__init__('hdc/transactions', server, port) - - -class Process(Base): - """POST a transaction.""" - - def __post__(self, **kwargs): - assert 'transaction' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/process', **kwargs).json() - - -class Last(Base): - """GET the last received transaction.""" - - def __init__(self, count=None, server=None, port=None): - """ - Arguments: - - `count`: Integer indicating to - retrieve the last [COUNT] transactions. - """ - - super().__init__(server, port) - - self.count = count - - def __get__(self, **kwargs): - if not self.count: - return self.requests_get('/last', **kwargs).json() - - return self.requests_get('/last/%d' % self.count, **kwargs).json() - - -class Sender(Base): - """GET all the transactions sent by this sender and stored - by this node (should contain all transactions of the sender).""" - - def __init__(self, pgp_fingerprint, begin=None, end=None, server=None, port=None): - """ - Arguments: - - `pgp_fingerprint`: PGP fingerprint of the - key we want to see sent transactions. - - `begin`: integer value used by the - merkle parser to know when to begin requesting. - - `end`: integer value used by the - merkle parser to know when to end requesting. - """ - - super().__init__(server, port) - - self.pgp_fingerprint = pgp_fingerprint - self.begin = begin - self.end = end - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/sender/%s' % self.pgp_fingerprint, - begin=self.begin, end=self.end) - - -class Recipient(Base): - """GET all the transactions received for - this recipient stored by this node.""" - - def __init__(self, pgp_fingerprint, begin=None, end=None, - server=None, port=None): - """ - Arguments: - - `pgp_fingerprint`: PGP fingerprint of the - key we want to see sent transactions. - - `begin`: integer value used by the - merkle parser to know when to begin requesting. - - `end`: integer value used by the - merkle parser to know when to end requesting. - """ - - super().__init__(server, port) - - self.pgp_fingerprint = pgp_fingerprint - self.begin = begin - self.end = end - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/recipient/%s' % self.pgp_fingerprint, - begin=self.begin, end=self.end) - - -#TODO: Manager /refering/pgp_fingerprint/tx_number/ -class Refering(Base): - """GET all the transactions refering to source - transaction #[TX_NUMBER] issued by [PGP_FINGERPRINT].""" - - def __init__(self, pgp_fingerprint, tx_number, server=None, port=None): - """ - Arguments: - - `transaction_id`: The transaction unique identifier. - """ - - super().__init__(server, port) - - self.pgp_fingerprint = pgp_fingerprint - self.tx_number = tx_number - - def __get__(self, **kwargs): - return self.requests_get('/refering/%s/%d' - % (self.pgp_fingerprint, self.tx_number), - **kwargs).json() - -from . import sender diff --git a/lib/ucoin/hdc/transactions/sender/__init__.py b/lib/ucoin/hdc/transactions/sender/__init__.py deleted file mode 100644 index 0a231c94..00000000 --- a/lib/ucoin/hdc/transactions/sender/__init__.py +++ /dev/null @@ -1,80 +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 HDC -from ... import logging - -logger = logging.getLogger("ucoin/hdc/transactions/sender") - - -class Base(HDC): - """Get the last received transaction of a PGP key.""" - - def __init__(self, pgp_fingerprint, server=None, port=None): - """ - Arguments: - - `pgp_fingerprint`: PGP fingerprint of the key - we want to see sent transactions. - """ - - super().__init__('hdc/transactions/sender/%s' % pgp_fingerprint, - server, port) - - -class Last(Base): - """Get the last received transaction of a PGP key.""" - - def __init__(self, pgp_fingerprint, count=None, from_=None, - server=None, port=None): - """ - Arguments: - - `count`: Integer indicating to retrieve the last [COUNT] transactions - """ - - super().__init__(pgp_fingerprint, server, port) - - self.count = count - self.from_ = from_ - - def __get__(self, **kwargs): - if not self.count: - return self.requests_get('/last', **kwargs).json() - - if not self.from_: - return self.requests_get('/last/%d' % self.count, **kwargs).json() - - return self.requests_get('/last/%d/%d' % (self.count, self.from_), - **kwargs).json() - - -class View(Base): - """GET the transaction of given TRANSACTION_ID.""" - - def __init__(self, pgp_fingerprint, tx_number, - server=None, port=None): - """ - Arguments: - - `count`: Integer indicating to retrieve the last [COUNT] transactions - """ - - super().__init__(pgp_fingerprint, server, port) - - self.tx_number = tx_number - - def __get__(self, **kwargs): - return self.requests_get('/view/%d' % self.tx_number, **kwargs).json() diff --git a/lib/ucoin/network/__init__.py b/lib/ucoin/network/__init__.py deleted file mode 100644 index e9111a3e..00000000 --- a/lib/ucoin/network/__init__.py +++ /dev/null @@ -1,72 +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 -from .. import logging - -logger = logging.getLogger("ucoin/network") - - -class Network(API): - def __init__(self, module='network', server=None, port=None): - super().__init__(module=module, server=server, port=port) - - -class Pubkey(Network): - """GET the public key of the peer.""" - - def __get__(self, **kwargs): - return self.requests_get('/pubkey', **kwargs).text - - -class Peering(Network): - """GET peering information about a peer.""" - - def __get__(self, **kwargs): - return self.requests_get('/peering', **kwargs).json() - - -class Wallet(Network): - """GET/POST Wallet entries.""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Use the pgp fingerprint parameter in order to fit the result. - - Arguments: - - `pgp_fingerprint`: pgp fingerprint to use as a filter - """ - - super().__init__(server=server, port=port) - - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - if not self.pgp_fingerprint: - return self.merkle_easy_parser('/wallet') - - return self.requests_get('/wallet/%s' % self.pgp_fingerprint, - **kwargs).json() - - def __post__(self, **kwargs): - assert 'entry' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/wallet', **kwargs) - -from . import peering diff --git a/lib/ucoin/network/peering/peers.py b/lib/ucoin/network/peering/peers.py deleted file mode 100644 index fe91e2c2..00000000 --- a/lib/ucoin/network/peering/peers.py +++ /dev/null @@ -1,77 +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 -from .. import logging - -logger = logging.getLogger("ucoin/network/peering/peers") - -class Base(Network): - def __init__(self, server=None, port=None): - super().__init__('network/peering/peers', server, port) - -class Stream(Base): - """GET a list of peers this node is listening to/by for ANY incoming transaction.""" - - def __init__(self, request, pgp_fingerprint=None, server=None, port=None): - """ - Use the pgp fingerprint parameter in order to fit the result. - - Arguments: - - `request`: select the stream request - - `pgp_fingerprint`: pgp fingerprint to use as a filter - """ - - super().__init__(server, port) - - self.request = request - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - """returns the corresponding peer list.""" - if self.pgp_fingerprint is None: - return self.requests_get('/%s' % (self.request), **kwargs).json() - else: - return self.requests_get('/%s/%s' % (self.request, self.pgp_fingerprint), **kwargs).json() - - -class UpStream(Stream): - """GET a list of peers this node is listening to for ANY incoming transaction.""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Use the pgp fingerprint parameter in order to fit the result. - - Arguments: - - `pgp_fingerprint`: pgp fingerprint to use as a filter - """ - - super().__init__('upstream', pgp_fingerprint, server, port) - - -class DownStream(Stream): - """GET a list of peers this node is listening by for ANY incoming transaction.""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Use the pgp fingerprint parameter in order to fit the result. - - Arguments: - - `pgp_fingerprint`: pgp fingerprint to use as a filter - """ - - super().__init__('downstream', pgp_fingerprint, server, port) diff --git a/lib/ucoin/pks/__init__.py b/lib/ucoin/pks/__init__.py deleted file mode 100644 index ecb92cac..00000000 --- a/lib/ucoin/pks/__init__.py +++ /dev/null @@ -1,60 +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 -from .. import logging - -logger = logging.getLogger("ucoin/pks") - - -class PKS(API): - def __init__(self, module='pks', server=None, port=None): - super().__init__(module=module, server=server, port=port) - - -class Add(PKS): - """POST ASCII-armored OpenPGP certificates.""" - - def __post__(self, **kwargs): - assert 'keytext' in kwargs - assert 'keysign' in kwargs - - return self.requests_post('/add', **kwargs) - - -class Lookup(PKS): - """Allows to search for OpenPGP certificates, according to HKP draft.""" - - def __get__(self, **kwargs): - assert 'search' in kwargs - assert 'op' in kwargs - - r = self.requests_get('/lookup', **kwargs) - - if kwargs['op'] == 'get': return r.text - - return r.json() - - -class All(PKS): - """GET all the received public keys.""" - - def __get__(self, **kwargs): - """creates a generator with one public key per iteration.""" - - return self.merkle_easy_parser('/all') diff --git a/lib/ucoin/registry/__init__.py b/lib/ucoin/registry/__init__.py deleted file mode 100644 index 8053bd58..00000000 --- a/lib/ucoin/registry/__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/>. -# - -from .. import API -from .. import logging - -logger = logging.getLogger("ucoin/registry") - - -class Registry(API): - def __init__(self, module='registry', server=None, port=None): - super().__init__(module=module, server=server, port=port) - - -class Parameters(Registry): - """GET parameters used by this community.""" - - def __get__(self, **kwargs): - return self.requests_get('/parameters', **kwargs).json() - - -class Amendment(Registry): - """GET parameters used by this community.""" - - def __get__(self, **kwargs): - return self.requests_get('/amendment', **kwargs).json() - -from . import amendment -from . import community \ No newline at end of file diff --git a/lib/ucoin/registry/amendment/__init__.py b/lib/ucoin/registry/amendment/__init__.py deleted file mode 100644 index 7ef12380..00000000 --- a/lib/ucoin/registry/amendment/__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/>. -# - -from .. import Registry -from .. import logging - -logger = logging.getLogger("ucoin/registry") - - -class Base(Registry): - def __init__(self, server=None, port=None): - super().__init__('registry/amendment', server, port) - - -class Vote(Base): - - """GET the vote of current node for given amendment number - (both amendment + signature). - Such vote may be used by any node to broadcast the whole network.""" - - def __init__(self, am_number=None, server=None, port=None): - super().__init__(server, port) - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/%s/vote' % self.am_number) diff --git a/lib/ucoin/registry/community/__init__.py b/lib/ucoin/registry/community/__init__.py deleted file mode 100644 index 8a46e04c..00000000 --- a/lib/ucoin/registry/community/__init__.py +++ /dev/null @@ -1,54 +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/>. -# - -from .. import Registry -from .. import logging - -logger = logging.getLogger("ucoin/registry") - - -class Base(Registry): - def __init__(self, server=None, port=None): - super().__init__('registry/community', server, port) - - -class Members(Base): - """GET the members present in the Community for this amendment.""" - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/members') - - def __post__(self, **kwargs): - assert 'membership' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/members', **kwargs) - - -class Voters(Base): - """GET the voters listed in this amendment.""" - - def __get__(self, **kwargs): - return self.merkle_easy_parser('/voters') - - def __post__(self, **kwargs): - assert 'voting' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/voters', **kwargs) - - -from . import members -from . import voters diff --git a/lib/ucoin/registry/community/members.py b/lib/ucoin/registry/community/members.py deleted file mode 100644 index 4b8d5bd4..00000000 --- a/lib/ucoin/registry/community/members.py +++ /dev/null @@ -1,60 +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/>. -# -# - -from . import Base -from .. import logging - -logger = logging.getLogger("ucoin/registry/community") - - -class Current(Base): - """GET the last valid membership document for member pgp_fingerprint""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Uses number to fit the result. - - Arguments: - - `number`: amendment number - """ - - super().__init__(server=server, port=port) - - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - return self.requests_get('/members/%s/current' % self.pgp_fingerprint, - **kwargs).json() - - -class History(Base): - """GET the all received and stored membership documents""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Uses number to fit the result. - - Arguments: - - `number`: amendment number - """ - - super().__init__(server=server, port=port) - - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - return self.requests_get('/members/%s/history' % self.pgp_fingerprint, - **kwargs).json() diff --git a/lib/ucoin/registry/community/voters.py b/lib/ucoin/registry/community/voters.py deleted file mode 100644 index 4a042064..00000000 --- a/lib/ucoin/registry/community/voters.py +++ /dev/null @@ -1,59 +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/>. -# -# - -from . import Base -from .. import logging - -logger = logging.getLogger("ucoin/registry/community") - -class Current(Base): - """GET the last valid membership document for member pgp_fingerprint""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Uses number to fit the result. - - Arguments: - - `number`: amendment number - """ - - super().__init__(server=server, port=port) - - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - return self.requests_get('/voters/%s/current' % self.pgp_fingerprint, - **kwargs).json() - - -class History(Base): - """GET the all received and stored membership documents""" - - def __init__(self, pgp_fingerprint=None, server=None, port=None): - """ - Uses number to fit the result. - - Arguments: - - `number`: amendment number - """ - - super().__init__(server=server, port=port) - - self.pgp_fingerprint = pgp_fingerprint - - def __get__(self, **kwargs): - return self.requests_get('/voters/%s/history' % self.pgp_fingerprint, - **kwargs).json() diff --git a/lib/ucoin/hdc/__init__.py b/lib/ucoinpy/__init__.py similarity index 71% rename from lib/ucoin/hdc/__init__.py rename to lib/ucoinpy/__init__.py index 701e3513..0eb79a46 100644 --- a/lib/ucoin/hdc/__init__.py +++ b/lib/ucoinpy/__init__.py @@ -15,15 +15,3 @@ # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr # - -from .. import API -from .. import logging - -logger = logging.getLogger("ucoin/hdc") - - -class HDC(API): - def __init__(self, module='hdc', server=None, port=None): - super().__init__(module=module, server=server, port=port) - -from . import amendments, coins, transactions diff --git a/lib/ucoinpy/bma/__init__.py b/lib/ucoinpy/bma/__init__.py new file mode 100644 index 00000000..fbd95eaa --- /dev/null +++ b/lib/ucoinpy/bma/__init__.py @@ -0,0 +1,139 @@ +# +# 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 +# + + +__all__ = ['api'] + +__author__ = 'Caner Candan' +__version__ = '0.10.0' +__nonsense__ = 'uCoin' + +import requests, logging, json +# import pylibscrypt + +logger = logging.getLogger("ucoin") + + +class ConnectionHandler(object): + """Helper class used by other API classes to ease passing server connection information.""" + + def __init__(self, server, port): + """ + Arguments: + - `server`: server hostname + - `port`: port number + """ + + 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, connection_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.connection_handler = connection_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.connection_handler.server, self.connection_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 + """ + + response = requests.get(self.reverse_url(path), params=kwargs, headers=self.headers) + + if response.status_code != 200: + raise ValueError('status code != 200 => %d (%s)' % (response.status_code, response.text)) + + return response + + def requests_post(self, path, **kwargs): + """ + Requests POST wrapper in order to use API parameters. + + Arguments: + - `path`: the request path + """ + + response = requests.post(self.reverse_url(path), data=kwargs, headers=self.headers) + + if response.status_code != 200: + raise ValueError('status code != 200 => %d (%s)' % (response.status_code, 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 diff --git a/lib/ucoinpy/bma/blockchain/__init__.py b/lib/ucoinpy/bma/blockchain/__init__.py new file mode 100644 index 00000000..e4e02c45 --- /dev/null +++ b/lib/ucoinpy/bma/blockchain/__init__.py @@ -0,0 +1,95 @@ +# +# 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, connection_handler, module='blockchain'): + super(Blockchain, self).__init__(connection_handler, module) + + +class Parameters(Blockchain): + """GET the blockchain parameters used by this node.""" + + def __get__(self, **kwargs): + return self.requests_get('/parameters', **kwargs).json() + + +class Membership(Blockchain): + """POST a Membership document.""" + + def __post__(self, **kwargs): + assert 'membership' in kwargs + + return self.requests_post('/membership', **kwargs).json() + + +class Block(Blockchain): + """GET/POST a block from/to the blockchain.""" + + def __init__(self, connection_handler, number=None): + """ + Use the number parameter in order to select a block number. + + Arguments: + - `number`: block number to select + """ + + super(Block, self).__init__(connection_handler) + + self.number = number + + def __get__(self, **kwargs): + assert self.number is not None + return self.requests_get('/block/%d' % self.number, **kwargs).json() + + def __post__(self, **kwargs): + assert 'block' in kwargs + assert 'signature' in kwargs + + return self.requests_post('/block', **kwargs).json() + + +class Current(Blockchain): + """GET, same as block/[number], but return last accepted block.""" + + def __get__(self, **kwargs): + return self.requests_get('/current', **kwargs).json() + + +class Hardship(Blockchain): + """GET hardship level for given member's fingerprint for writing next block.""" + + def __init__(self, connection_handler, fingerprint): + """ + Use the number parameter in order to select a block number. + + Arguments: + - `fingerprint`: member fingerprint + """ + + super(Hardship, self).__init__(connection_handler) + + self.fingerprint = fingerprint + + def __get__(self, **kwargs): + assert self.fingerprint is not None + return self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs).json() diff --git a/lib/ucoin/hdc/coins/__init__.py b/lib/ucoinpy/bma/network/__init__.py similarity index 57% rename from lib/ucoin/hdc/coins/__init__.py rename to lib/ucoinpy/bma/network/__init__.py index eccd7d75..3d6c73ec 100644 --- a/lib/ucoin/hdc/coins/__init__.py +++ b/lib/ucoinpy/bma/network/__init__.py @@ -16,25 +16,20 @@ # Caner Candan <caner@candan.fr>, http://caner.candan.fr # -from .. import HDC -from .. import logging +from .. import API, logging -logger = logging.getLogger("ucoin/hdc/coins") +logger = logging.getLogger("ucoin/network") -class Coins(HDC): - def __init__(self, server=None, port=None): - super().__init__('hdc/coins', server, port) +class Network(API): + def __init__(self, connection_handler, module='network'): + super(Network, self).__init__(connection_handler, module) -class List(Coins): - def __init__(self, pgp_fingerprint, server=None, port=None): - super().__init__(server=server, port=port) - self.pgp_fingerprint = pgp_fingerprint - - """GET a list of coins owned by [PGP_FINGERPRINT].""" +class Peering(Network): + """GET peering information about a peer.""" def __get__(self, **kwargs): - return self.requests_get('/list/%s' % self.pgp_fingerprint, **kwargs).json() + return self.requests_get('/peering', **kwargs).json() -from . import view +from . import peering diff --git a/lib/ucoin/network/peering/__init__.py b/lib/ucoinpy/bma/network/peering/__init__.py similarity index 69% rename from lib/ucoin/network/peering/__init__.py rename to lib/ucoinpy/bma/network/peering/__init__.py index b238f0a8..3ad7cde3 100644 --- a/lib/ucoin/network/peering/__init__.py +++ b/lib/ucoinpy/bma/network/peering/__init__.py @@ -14,17 +14,16 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -#networkfrom .. import UCG, logging +# -from .. import Network -from .. import logging +from .. import Network, logging logger = logging.getLogger("ucoin/network/peering") class Base(Network): - def __init__(self, server=None, port=None): - super().__init__(module='network/peering', server=server, port=port) + def __init__(self, connection_handler): + super(Base, self).__init__(connection_handler, 'network/peering') class Peers(Base): @@ -41,22 +40,12 @@ class Peers(Base): return self.requests_post('/peers', **kwargs).json() -class Forward(Base): - """POST a UCG forward document to this node in order to be sent back incoming transactions.""" - - def __post__(self, **kwargs): - assert 'forward' in kwargs - assert 'signature' in kwargs - - return self.requests_post('/forward', **kwargs).json() class Status(Base): - """POST a UCG status document to this node in order notify of its status.""" + """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).json() - -from . import peers diff --git a/lib/ucoin/hdc/coins/view.py b/lib/ucoinpy/bma/tx/__init__.py similarity index 55% rename from lib/ucoin/hdc/coins/view.py rename to lib/ucoinpy/bma/tx/__init__.py index 8489bc01..a7adc5f3 100644 --- a/lib/ucoin/hdc/coins/view.py +++ b/lib/ucoinpy/bma/tx/__init__.py @@ -16,27 +16,29 @@ # Caner Candan <caner@candan.fr>, http://caner.candan.fr # -from .. import HDC -from .. import logging +from .. import API, logging -logger = logging.getLogger("ucoin/hdc/coins/view") +logger = logging.getLogger("ucoin/tx") -class Base(HDC): - def __init__(self, coin_id, server=None, port=None): - super().__init__('hdc/coins/view/%s' % coin_id, server, port) +class Tx(API): + def __init__(self, connection_handler, module='tx'): + super(Tx, self).__init__(connection_handler, module) -class Owner(Base): - """GET a coin owner + justifying transaction if it exists.""" +class Process(Tx): + """POST a transaction.""" - def __get__(self, **kwargs): - return self.requests_get('/owner', **kwargs).json() + def __post__(self, **kwargs): + assert 'transaction' in kwargs + assert 'signature' in kwargs + + return self.requests_post('/process', **kwargs).json() -class History(Base): - """GET a coin owner + justifying transaction - for each state a coin has gone trough.""" +class Sources(Tx): + """Get transaction sources.""" def __get__(self, **kwargs): - return self.requests_get('/history', **kwargs).json() + assert self.pubkey is not None + return self.requests_get('/sources/%d' % self.pubkey, **kwargs).json() diff --git a/lib/ucoinpy/bma/wot/__init__.py b/lib/ucoinpy/bma/wot/__init__.py new file mode 100644 index 00000000..aa1ca0de --- /dev/null +++ b/lib/ucoinpy/bma/wot/__init__.py @@ -0,0 +1,51 @@ +# +# 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, connection_handler, module='wot'): + super(WOT, self).__init__(connection_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).json() + + +class Lookup(WOT): + """GET Public key data.""" + + def __init__(self, connection_handler, search, module='wot'): + super(WOT, self).__init__(connection_handler, module) + + self.search = search + + def __get__(self, **kwargs): + assert self.search is not None + + return self.requests_get('/lookup/%s' % self.search, **kwargs).json() -- GitLab