diff --git a/lib/ucoinpy/__init__.py b/lib/ucoinpy/__init__.py deleted file mode 100644 index 3b1345bc8e6afcb68399f864af138a40ab4cbe0f..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/__init__.py +++ /dev/null @@ -1,23 +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 -# - -PROTOCOL_VERSION="1" - -MANAGED_API=["BASIC_MERKLED_API"] - -from . import api, documents, key \ No newline at end of file diff --git a/lib/ucoinpy/api/__init__.py b/lib/ucoinpy/api/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/lib/ucoinpy/api/bma/__init__.py b/lib/ucoinpy/api/bma/__init__.py deleted file mode 100644 index 006f3b2eb75d50d6c0f881cb41f43b6467204acd..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/__init__.py +++ /dev/null @@ -1,141 +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__ = 'Caner Candan' -__version__ = '0.11.0' -__nonsense__ = 'uCoin' - -PROTOCOL_VERSION = "1" - -import aiohttp, asyncio, logging, json - -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 - self.connector = None - - 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.""" - - aiohttp_connector = None - - 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 - - @asyncio.coroutine - def requests_get(self, path, **kwargs): - """ - Requests GET wrapper in order to use API parameters. - - 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, connector=API.aiohttp_connector), timeout=30) - - if response.status != 200: - raise ValueError('status code != 200 => %d (%s)' % (response.status, (yield from response.text()))) - - return response - - 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)) - response = yield from asyncio.wait_for( - aiohttp.post(self.reverse_url(path), data=kwargs, headers=self.headers, - connector=API.aiohttp_connector), - timeout=30) - return response - -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 deleted file mode 100644 index 8e465ec99ea2b8d48413f263d093032dda3115fc..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/blockchain/__init__.py +++ /dev/null @@ -1,173 +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, 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): - r = yield from self.requests_get('/parameters', **kwargs) - return (yield from r.json()) - - -class Membership(Blockchain): - """GET/POST a Membership document.""" - def __init__(self, connection_handler, search=None): - super().__init__(connection_handler) - self.search = search - - def __post__(self, **kwargs): - assert 'membership' in kwargs - - r = yield from self.requests_post('/membership', **kwargs) - return r - - def __get__(self, **kwargs): - assert self.search is not None - r = yield from self.requests_get('/memberships/%s' % self.search, **kwargs) - return (yield from r.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 - 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 - - r = yield from self.requests_post('/block', **kwargs) - return r - - -class Current(Blockchain): - """GET, same as block/[number], but return last accepted block.""" - - def __get__(self, **kwargs): - r = yield from self.requests_get('/current', **kwargs) - return (yield from r.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 - 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): - 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): - 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): - 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): - 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): - 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): - 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): - 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): - 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 deleted file mode 100644 index 860674c98ea6749d7593f2ff7da10dd6f0f6fff0..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/network/__init__.py +++ /dev/null @@ -1,36 +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, connection_handler, module='network'): - super(Network, self).__init__(connection_handler, module) - - -class Peering(Network): - """GET peering information about a peer.""" - - def __get__(self, **kwargs): - 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 deleted file mode 100644 index 36ca7915ff52b9ef7097ef7bb55be9f56bdf55ea..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/network/peering/__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/>. -# -# 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, connection_handler): - super(Base, self).__init__(connection_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.""" - - 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 - - r = yield from self.requests_post('/peers', **kwargs) - return r - - -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 - - r = yield from self.requests_post('/status', **kwargs) - return r diff --git a/lib/ucoinpy/api/bma/node/__init__.py b/lib/ucoinpy/api/bma/node/__init__.py deleted file mode 100644 index f156578757aeb3056e404490a1629ce1c3659790..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/node/__init__.py +++ /dev/null @@ -1,38 +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): - 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 deleted file mode 100644 index 23ba91db03fc371febd6c2cb75e869f82342e3c6..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/tx/__init__.py +++ /dev/null @@ -1,62 +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, connection_handler, module='tx'): - 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 - - r = yield from self.requests_post('/process', **kwargs) - return r - - -class Sources(Tx): - """Get transaction sources.""" - def __init__(self, connection_handler, pubkey, module='tx'): - super(Tx, self).__init__(connection_handler, module) - self.pubkey = pubkey - - def __get__(self, **kwargs): - assert self.pubkey is not None - 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/tx/history/__init__.py b/lib/ucoinpy/api/bma/tx/history/__init__.py deleted file mode 100644 index b0e42968a817b6560c80602afca9587738640d00..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/tx/history/__init__.py +++ /dev/null @@ -1,32 +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_ - - def __get__(self, **kwargs): - r = yield from self.requests_get('/history/%s/blocks/%s/%s' % (self.pubkey, self.from_, self.to_), **kwargs) - return (yield from r.json()) \ No newline at end of file diff --git a/lib/ucoinpy/api/bma/ud/__init__.py b/lib/ucoinpy/api/bma/ud/__init__.py deleted file mode 100644 index 33f51b2ff52f9b1faaa1bf7ae2e718aec82783cf..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/ud/__init__.py +++ /dev/null @@ -1,39 +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.""" - - 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 - r = yield from self.requests_get('/history/%s' % self.pubkey, **kwargs) - return (yield from r.json()) diff --git a/lib/ucoinpy/api/bma/wot/__init__.py b/lib/ucoinpy/api/bma/wot/__init__.py deleted file mode 100644 index 83fd51848909b2f1563043ff89e5203a10ff231a..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/api/bma/wot/__init__.py +++ /dev/null @@ -1,105 +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, 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 - - r = yield from self.requests_post('/add', **kwargs) - return r - - -class Revoke(WOT): - """POST Public key data.""" - - def __post__(self, **kwargs): - assert 'pubkey' in kwargs - assert 'self_' in kwargs - - r = yield from self.requests_post('/revoke', **kwargs) - return r - - -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 - - r = yield from self.requests_get('/lookup/%s' % self.search, **kwargs) - return (yield from r.json()) - - -class CertifiersOf(WOT): - """GET Certification data over a member.""" - - 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 - - r = yield from self.requests_get('/certifiers-of/%s' % self.search, **kwargs) - return (yield from r.json()) - - -class CertifiedBy(WOT): - """GET Certification data from a member.""" - - 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 - - r = yield from self.requests_get('/certified-by/%s' % self.search, **kwargs) - return (yield from r.json()) - - -class Members(WOT): - """GET List all current members of the Web of Trust.""" - - def __init__(self, connection_handler, module='wot'): - super(WOT, self).__init__(connection_handler, module) - - def __get__(self, **kwargs): - r = yield from self.requests_get('/members', **kwargs) - return (yield from r.json()) diff --git a/lib/ucoinpy/documents/__init__.py b/lib/ucoinpy/documents/__init__.py deleted file mode 100644 index 2291e35a028452620bc12c2101ee2fd5a4bb8220..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .block import Block, BlockId -from .certification import SelfCertification, Certification -from .membership import Membership -from .peer import Endpoint, BMAEndpoint, UnknownEndpoint, Peer -from .status import Status -from .transaction import SimpleTransaction, Transaction -from .document import Document \ No newline at end of file diff --git a/lib/ucoinpy/documents/block.py b/lib/ucoinpy/documents/block.py deleted file mode 100644 index 81fafccca05300252fe4c2edeb54d7a5fca262e7..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/block.py +++ /dev/null @@ -1,332 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" - -from .. import PROTOCOL_VERSION -from .document import Document -from .certification import SelfCertification, Certification -from .membership import Membership -from .transaction import Transaction - -import re -import logging - - -class BlockId: - """ - A simple block id - """ - re_hash = re.compile("([0-9a-fA-F]{5,40})") - - @classmethod - def empty(cls): - return cls(0, Block.Empty_Hash) - - def __init__(self, number, sha_hash): - assert(type(number) is int) - assert(BlockId.re_hash.match(sha_hash) is not None) - self.number = number - self.sha_hash = sha_hash - - @classmethod - def from_str(cls, blockid): - """ - :param str blockid: The block id - """ - data = blockid.split("-") - number = int(data[0]) - sha_hash = data[1] - return cls(number, sha_hash) - - def __str__(self): - return "{0}-{1}".format(self.number, self.sha_hash) - - -class Block(Document): - """ -Version: VERSION -Type: Block -Currency: CURRENCY -Nonce: NONCE -Number: BLOCK_NUMBER -PoWMin: NUMBER_OF_ZEROS -Time: GENERATED_ON -MedianTime: MEDIAN_DATE -UniversalDividend: DIVIDEND_AMOUNT -Issuer: ISSUER_KEY -PreviousHash: PREVIOUS_HASH -PreviousIssuer: PREVIOUS_ISSUER_KEY -Parameters: PARAMETERS -MembersCount: WOT_MEM_COUNT -Identities: -PUBLIC_KEY:SIGNATURE:TIMESTAMP:USER_ID -... -Joiners: -PUBLIC_KEY:SIGNATURE:NUMBER:HASH:TIMESTAMP:USER_ID -... -Actives: -PUBLIC_KEY:SIGNATURE:NUMBER:HASH:TIMESTAMP:USER_ID -... -Leavers: -PUBLIC_KEY:SIGNATURE:NUMBER:HASH:TIMESTAMP:USER_ID -... -Excluded: -PUBLIC_KEY -... -Certifications: -PUBKEY_FROM:PUBKEY_TO:BLOCK_NUMBER:SIGNATURE -... -Transactions: -COMPACT_TRANSACTION -... -BOTTOM_SIGNATURE - """ - - re_type = re.compile("Type: (Block)\n") - re_noonce = re.compile("Nonce: ([0-9]+)\n") - re_number = re.compile("Number: ([0-9]+)\n") - re_powmin = re.compile("PoWMin: ([0-9]+)\n") - re_time = re.compile("Time: ([0-9]+)\n") - re_mediantime = re.compile("MedianTime: ([0-9]+)\n") - re_universaldividend = re.compile("UniversalDividend: ([0-9]+)\n") - re_issuer = re.compile("Issuer: ([1-9A-Za-z][^OIl]{42,45})\n") - re_previoushash = re.compile("PreviousHash: ([0-9a-fA-F]{5,40})\n") - re_previousissuer = re.compile("PreviousIssuer: ([1-9A-Za-z][^OIl]{42,45})\n") - re_parameters = re.compile("Parameters: ([0-9]+\.[0-9]+):([0-9]+):([0-9]+):([0-9]+):\ -([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):\ -([0-9]+\.[0-9]+)\n") - re_memberscount = re.compile("MembersCount: ([0-9]+)\n") - re_identities = re.compile("Identities:\n") - re_joiners = re.compile("Joiners:\n") - re_actives = re.compile("Actives:\n") - re_leavers = re.compile("Leavers:\n") - re_excluded = re.compile("Excluded:\n") - re_exclusion = re.compile("([1-9A-Za-z][^OIl]{42,45})\n") - re_certifications = re.compile("Certifications:\n") - re_transactions = re.compile("Transactions:\n") - - Empty_Hash = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709" - - def __init__(self, version, currency, noonce, number, powmin, time, - mediantime, ud, issuer, prev_hash, prev_issuer, - parameters, members_count, identities, joiners, - actives, leavers, excluded, certifications, - transactions, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - self.noonce = noonce - self.number = number - self.powmin = powmin - self.time = time - self.mediantime = mediantime - self.ud = ud - self.issuer = issuer - self.prev_hash = prev_hash - self.prev_issuer = prev_issuer - self.parameters = parameters - self.members_count = members_count - self.identities = identities - self.joiners = joiners - self.actives = actives - self.leavers = leavers - self.excluded = excluded - self.certifications = certifications - self.transactions = transactions - - @property - def blockid(self): - return BlockId(self.number, self.sha_hash) - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Block.re_version.match(lines[n]).group(1)) - n = n + 1 - - Block.re_type.match(lines[n]).group(1) - n = n + 1 - - currency = Block.re_currency.match(lines[n]).group(1) - n = n + 1 - - noonce = int(Block.re_noonce.match(lines[n]).group(1)) - n = n + 1 - - number = int(Block.re_number.match(lines[n]).group(1)) - n = n + 1 - - powmin = int(Block.re_powmin.match(lines[n]).group(1)) - n = n + 1 - - time = int(Block.re_time.match(lines[n]).group(1)) - n = n + 1 - - mediantime = int(Block.re_mediantime.match(lines[n]).group(1)) - n = n + 1 - - ud = Block.re_universaldividend.match(lines[n]) - if ud is not None: - ud = int(ud.group(1)) - n = n + 1 - - issuer = Block.re_issuer.match(lines[n]).group(1) - n = n + 1 - - prev_hash = None - prev_issuer = None - if number > 0: - prev_hash = Block.re_previoushash.match(lines[n]).group(1) - n = n + 1 - - prev_issuer = Block.re_previousissuer.match(lines[n]).group(1) - n = n + 1 - - parameters = None - if number == 0: - parameters = Block.re_parameters.match(lines[n]).groups() - n = n + 1 - - members_count = int(Block.re_memberscount.match(lines[n]).group(1)) - n = n + 1 - - identities = [] - joiners = [] - actives = [] - leavers = [] - excluded = [] - certifications = [] - transactions = [] - - if Block.re_identities.match(lines[n]) is not None: - n = n + 1 - while Block.re_joiners.match(lines[n]) is None: - selfcert = SelfCertification.from_inline(version, currency, lines[n]) - identities.append(selfcert) - n = n + 1 - - if Block.re_joiners.match(lines[n]): - n = n + 1 - while Block.re_actives.match(lines[n]) is None: - membership = Membership.from_inline(version, currency, "IN", lines[n]) - joiners.append(membership) - n = n + 1 - - if Block.re_actives.match(lines[n]): - n = n + 1 - while Block.re_leavers.match(lines[n]) is None: - membership = Membership.from_inline(version, currency, "IN", lines[n]) - actives.append(membership) - n = n + 1 - - if Block.re_leavers.match(lines[n]): - n = n + 1 - while Block.re_excluded.match(lines[n]) is None: - membership = Membership.from_inline(version, currency, "OUT", lines[n]) - leavers.append(membership) - n = n + 1 - - if Block.re_excluded.match(lines[n]): - n = n + 1 - while Block.re_certifications.match(lines[n]) is None: - membership = Block.re_exclusion.match(lines[n]).group(1) - excluded.append(membership) - n = n + 1 - - if Block.re_certifications.match(lines[n]): - n = n + 1 - while Block.re_transactions.match(lines[n]) is None: - certification = Certification.from_inline(version, currency, - prev_hash, lines[n]) - certifications.append(certification) - n = n + 1 - - if Block.re_transactions.match(lines[n]): - n = n + 1 - while not Block.re_signature.match(lines[n]): - tx_lines = "" - header_data = Transaction.re_header.match(lines[n]) - version = int(header_data.group(1)) - issuers_num = int(header_data.group(2)) - inputs_num = int(header_data.group(3)) - outputs_num = int(header_data.group(4)) - has_comment = int(header_data.group(5)) - tx_max = n+issuers_num*2+inputs_num+outputs_num+has_comment+1 - for i in range(n, tx_max): - tx_lines += lines[n] - n = n + 1 - transaction = Transaction.from_compact(currency, tx_lines) - transactions.append(transaction) - - signature = Block.re_signature.match(lines[n]).group(1) - - return cls(version, currency, noonce, number, powmin, time, - mediantime, ud, issuer, prev_hash, prev_issuer, - parameters, members_count, identities, joiners, - actives, leavers, excluded, certifications, - transactions, signature) - - def raw(self): - doc = """Version: {0} -Type: Block -Currency: {1} -Nonce: {2} -Number: {3} -PoWMin: {4} -Time: {5} -MedianTime: {6} -""".format(self.version, - self.currency, - self.noonce, - self.number, - self.powmin, - self.time, - self.mediantime) - if self.ud: - doc += "UniversalDividend: {0}\n".format(self.ud) - - doc += "Issuer: {0}\n".format(self.issuer) - - if self.number == 0: - str_params = ":".join(self.parameters) - doc += "Parameters: {0}\n".format(str_params) - else: - doc += "PreviousHash: {0}\n\ -PreviousIssuer: {1}\n".format(self.prev_hash, self.prev_issuer) - - doc += "MembersCount: {0}\n".format(self.members_count) - - doc += "Identities:\n" - for identity in self.identities: - doc += "{0}\n".format(identity.inline()) - - doc += "Joiners:\n" - for joiner in self.joiners: - doc += "{0}\n".format(joiner.inline()) - - doc += "Actives:\n" - for active in self.actives: - doc += "{0}\n".format(active.inline()) - - doc += "Leavers:\n" - for leaver in self.leavers: - doc += "{0]\n".format(leaver.inline()) - - doc += "Excluded:\n" - for exclude in self.excluded: - doc += "{0}\n".format(exclude) - - doc += "Certifications:\n" - for cert in self.certifications: - doc += "{0}\n".format(cert.inline()) - - doc += "Transactions:\n" - for transaction in self.transactions: - doc += "{0}\n".format(transaction.compact()) - - return doc \ No newline at end of file diff --git a/lib/ucoinpy/documents/certification.py b/lib/ucoinpy/documents/certification.py deleted file mode 100644 index 61999ccf4ca13f7baabe204e886ace19a917afa7..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/certification.py +++ /dev/null @@ -1,132 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" -import re -import base64 -import logging - -from .document import Document - - -class SelfCertification(Document): - """ - A document discribing a self certification. - """ - - re_inline = re.compile("([1-9A-Za-z][^OIl]{42,45}):([A-Za-z0-9+/]+(?:=|==)?):([0-9]+):([^\n]+)\n") - re_uid = re.compile("UID:([^\n]+)\n") - re_timestamp = re.compile("META:TS:([0-9]+)\n") - - def __init__(self, version, currency, pubkey, ts, uid, signature): - if signature: - super().__init__(version, currency, [signature]) - else: - super().__init__(version, currency, []) - self.pubkey = pubkey - self.timestamp = ts - self.uid = uid - - @classmethod - def from_inline(cls, version, currency, inline): - selfcert_data = SelfCertification.re_inline.match(inline) - pubkey = selfcert_data.group(1) - signature = selfcert_data.group(2) - ts = int(selfcert_data.group(3)) - uid = selfcert_data.group(4) - return cls(version, currency, pubkey, ts, uid, signature) - - def raw(self): - return """UID:{0} -META:TS:{1} -""".format(self.uid, self.timestamp) - - def inline(self): - return "{0}:{1}:{2}:{3}".format(self.pubkey, self.signatures[0], - self.timestamp, self.uid) - - -class Certification(Document): - """ - A document describing a certification. - """ - - re_inline = re.compile("([1-9A-Za-z][^OIl]{42,45}):\ -([1-9A-Za-z][^OIl]{42,45}):([0-9]+):([A-Za-z0-9+/]+(?:=|==)?)\n") - re_timestamp = re.compile("META:TS:([0-9]+)-([0-9a-fA-F]{5,40})\n") - - def __init__(self, version, currency, pubkey_from, pubkey_to, - blocknumber, blockhash, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - self.pubkey_from = pubkey_from - self.pubkey_to = pubkey_to - self.blockhash = blockhash - self.blocknumber = blocknumber - - @classmethod - def from_inline(cls, version, currency, blockhash, inline): - cert_data = Certification.re_inline.match(inline) - pubkey_from = cert_data.group(1) - pubkey_to = cert_data.group(2) - blocknumber = int(cert_data.group(3)) - if blocknumber == 0: - blockhash = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709" - signature = cert_data.group(4) - return cls(version, currency, pubkey_from, pubkey_to, - blockhash, blocknumber, signature) - - def raw(self, selfcert): - return """{0}META:TS:{1}-{2} -""".format(selfcert.signed_raw(), self.blocknumber, self.blockhash) - - - def sign(self, selfcert, keys): - """ - Sign the current document. - Warning : current signatures will be replaced with the new ones. - """ - self.signatures = [] - for key in keys: - signing = base64.b64encode(key.signature(bytes(self.raw(selfcert), 'ascii'))) - logging.debug("Signature : \n{0}".format(signing.decode("ascii"))) - self.signatures.append(signing.decode("ascii")) - - def signed_raw(self, selfcert): - raw = self.raw(selfcert) - signed = "\n".join(self.signatures) - signed_raw = raw + signed + "\n" - return signed_raw - - def inline(self): - return "{0}:{1}:{2}:{3}".format(self.pubkey_from, self.pubkey_to, - self.blocknumber, self.signatures[0]) - - -class Revocation(Document): - """ - A document describing a self-revocation. - """ - def __init__(self, version, currency, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - - def raw(self, selfcert): - return """{0}META:REVOKE -""".format(selfcert.signed_raw()) - - def sign(self, selfcert, keys): - """ - Sign the current document. - Warning : current signatures will be replaced with the new ones. - """ - self.signatures = [] - for key in keys: - signing = base64.b64encode(key.signature(bytes(self.raw(selfcert), 'ascii'))) - self.signatures.append(signing.decode("ascii")) - diff --git a/lib/ucoinpy/documents/document.py b/lib/ucoinpy/documents/document.py deleted file mode 100644 index 08025a6bfd29b073b95b4daf2f87fca312204cd2..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/document.py +++ /dev/null @@ -1,45 +0,0 @@ -import base58 -import base64 -import re -import logging -import hashlib -from ..key import Base58Encoder - - -class Document: - re_version = re.compile("Version: ([0-9]+)\n") - re_currency = re.compile("Currency: ([^\n]+)\n") - re_signature = re.compile("([A-Za-z0-9+/]+(?:=|==)?)\n") - - def __init__(self, version, currency, signatures): - self.version = version - self.currency = currency - if signatures: - self.signatures = [s for s in signatures if s is not None] - else: - self.signatures = [] - - def sign(self, keys): - """ - Sign the current document. - Warning : current signatures will be replaced with the new ones. - """ - self.signatures = [] - for key in keys: - signing = base64.b64encode(key.signature(bytes(self.raw(), 'ascii'))) - logging.debug("Signature : \n{0}".format(signing.decode("ascii"))) - self.signatures.append(signing.decode("ascii")) - - def signed_raw(self): - """ - If keys are None, returns the raw + current signatures - If keys are present, returns the raw signed by these keys - """ - raw = self.raw() - signed = "\n".join(self.signatures) - signed_raw = raw + signed + "\n" - return signed_raw - - @property - def sha_hash(self): - return hashlib.sha1(self.signed_raw().encode("ascii")).hexdigest().upper() diff --git a/lib/ucoinpy/documents/membership.py b/lib/ucoinpy/documents/membership.py deleted file mode 100644 index 097d36762c51b94d289b8123258991570baa248a..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/membership.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" -from .. import PROTOCOL_VERSION -from .document import Document - -import re - - -class Membership(Document): - """ - This is a utility class to generate membership documents : - Version: VERSION - Type: Membership - Currency: CURRENCY_NAME - Issuer: ISSUER - Block: NUMBER-HASH - Membership: MEMBERSHIP_TYPE - UserID: USER_ID - CertTS: CERTIFICATION_TS - """ - - # PUBLIC_KEY:SIGNATURE:NUMBER:HASH:TIMESTAMP:USER_ID - re_inline = re.compile("([1-9A-Za-z][^OIl]{42,45}):([A-Za-z0-9+/]+(?:=|==)?):\ -([0-9]+):([0-9a-fA-F]{5,40}):([0-9]+):([^\n]+)\n") - re_type = re.compile("Type: (Membership)") - re_issuer = re.compile("Issuer: ([1-9A-Za-z][^OIl]{42,45})\n") - re_block = re.compile("Block: ([0-9]+)-([0-9a-fA-F]{5,40})\n") - re_membership_type = re.compile("Membership: (IN|OUT)") - re_userid = re.compile("UserID: ([^\n]+)\n") - re_certts = re.compile("CertTS: ([0-9]+)\n") - - - - def __init__(self, version, currency, issuer, block_number, block_hash, - membership_type, uid, cert_ts, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - self.issuer = issuer - self.block_number = block_number - self.block_hash = block_hash - self.membership_type = membership_type - self.uid = uid - self.cert_ts = cert_ts - - @classmethod - def from_inline(cls, version, currency, membership_type, inline): - data = Membership.re_inline.match(inline) - issuer = data.group(1) - signature = data.group(2) - block_number = int(data.group(3)) - block_hash = data.group(4) - cert_ts = int(data.group(5)) - uid = data.group(6) - return cls(version, currency, issuer, block_number, - block_hash, membership_type, uid, cert_ts, signature) - - @classmethod - def from_signed_raw(cls, raw, signature=None): - lines = raw.splitlines(True) - n = 0 - - version = int(Membership.re_version.match(lines[n]).group(1)) - n = n + 1 - - Membership.re_type.match(lines[n]).group(1) - n = n + 1 - - currency = Membership.re_currency.match(lines[n]).group(1) - n = n + 1 - - issuer = Membership.re_issuer.match(lines[n]).group(1) - n = n + 1 - - blockid = Membership.re_block.match(lines[n]) - blocknumber = int(blockid.group(1)) - blockhash = blockid.group(2) - n = n + 1 - - membership_type = Membership.re_membership_type.match(lines[n]).group(1) - n = n + 1 - - uid = Membership.re_userid.match(lines[n]).group(1) - n = n + 1 - - cert_ts = int(Membership.re_certts.match(lines[n]).group(1)) - n = n + 1 - - signature = Membership.re_signature.match(lines[n]).group(1) - n = n + 1 - - return cls(version, currency, issuer, blocknumber, blockhash, - membership_type, uid, cert_ts, signature) - - def raw(self): - return """Version: {0} -Type: Membership -Currency: {1} -Issuer: {2} -Block: {3}-{4} -Membership: {5} -UserID: {6} -CertTS: {7} -""".format(self.version, - self.currency, - self.issuer, - self.block_number, self.block_hash, - self.membership_type, - self.uid, - self.cert_ts) - - def inline(self): - return "{0}:{1}:{2}:{3}:{4}:{5}".format(self.issuer, - self.signatures[0], - self.block_number, - self.block_hash, - self.cert_ts, - self.uid) diff --git a/lib/ucoinpy/documents/peer.py b/lib/ucoinpy/documents/peer.py deleted file mode 100644 index 80dddef7c73e65c6cc4893f357fd92697aa3f469..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/peer.py +++ /dev/null @@ -1,154 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" - -import re - -from ..api.bma import ConnectionHandler -from .document import Document -from .. import PROTOCOL_VERSION, MANAGED_API - - -class Peer(Document): - """ - Version: VERSION - Type: Peer - Currency: CURRENCY_NAME - PublicKey: NODE_PUBLICKEY - Block: BLOCK - Endpoints: - END_POINT_1 - END_POINT_2 - END_POINT_3 - [...] - """ - - re_type = re.compile("Type: (Peer)") - re_pubkey = re.compile("PublicKey: ([1-9A-Za-z][^OIl]{42,45})\n") - re_block = re.compile("Block: ([0-9]+-[0-9a-fA-F]{5,40})\n") - re_endpoints = re.compile("Endpoints:\n") - - def __init__(self, version, currency, pubkey, blockid, - endpoints, signature): - super().__init__(version, currency, [signature]) - - self.pubkey = pubkey - self.blockid = blockid - self.endpoints = endpoints - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Peer.re_version.match(lines[n]).group(1)) - n = n + 1 - - Peer.re_type.match(lines[n]).group(1) - n = n + 1 - - currency = Peer.re_currency.match(lines[n]).group(1) - n = n + 1 - - pubkey = Peer.re_pubkey.match(lines[n]).group(1) - n = n + 1 - - blockid = Peer.re_block.match(lines[n]).group(1) - n = n + 1 - - Peer.re_endpoints.match(lines[n]) - n = n + 1 - - endpoints = [] - while not Peer.re_signature.match(lines[n]): - endpoint = Endpoint.from_inline(lines[n]) - endpoints.append(endpoint) - n = n + 1 - - signature = Peer.re_signature.match(lines[n]).group(1) - - return cls(version, currency, pubkey, blockid, endpoints, signature) - - def raw(self): - doc = """Version: {0} -Type: Peer -Currency: {1} -PublicKey: {2} -Block: {3} -Endpoints: -""".format(self.version, self.currency, self.pubkey, self.blockid) - - for endpoint in self.endpoints: - doc += "{0}\n".format(endpoint.inline()) - - doc += "{0}\n".format(self.signatures[0]) - return doc - - -class Endpoint(): - """ - Describing endpoints - """ - - @staticmethod - def from_inline(inline): - for api in MANAGED_API: - if (inline.startswith(api)): - if (api == "BASIC_MERKLED_API"): - return BMAEndpoint.from_inline(inline) - return UnknownEndpoint.from_inline(inline) - - -class UnknownEndpoint(Endpoint): - - def __init__(self, api, properties): - self.api = api - self.properties = properties - - @classmethod - def from_inline(cls, inline): - api = inline.split()[0] - properties = inline.split()[1:] - return cls(api, properties) - - def inline(self): - doc = self.api - for p in self.properties: - doc += " {0}".format(p) - return doc - - -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]+))$') - - @classmethod - def from_inline(cls, inline): - m = BMAEndpoint.re_inline.match(inline) - server = m.group(1) - ipv4 = m.group(2) - ipv6 = m.group(3) - port = int(m.group(4)) - return cls(server, ipv4, ipv6, port) - - def __init__(self, server, ipv4, ipv6, port): - self.server = server - self.ipv4 = ipv4 - self.ipv6 = ipv6 - self.port = port - - def inline(self): - return "BASIC_MERKLED_API{DNS}{IPv4}{IPv6}{PORT}" \ - .format(DNS=(" {0}".format(self.server) if self.server else ""), - IPv4=(" {0}".format(self.ipv4) if self.ipv4 else ""), - IPv6=(" {0}".format(self.ipv6) if self.ipv6 else ""), - PORT=(" {0}".format(self.port) if self.port else "")) - - def conn_handler(self): - if self.server: - return ConnectionHandler(self.server, self.port) - elif self.ipv4: - return ConnectionHandler(self.ipv4, self.port) - else: - return ConnectionHandler(self.ipv6, self.port) diff --git a/lib/ucoinpy/documents/status.py b/lib/ucoinpy/documents/status.py deleted file mode 100644 index acfd5eb47654b41813a847eb36662fd6f75dae25..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/status.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" - -import re -from .document import Document - - -class Status(Document): - """ - Version: VERSION - Type: Status - Currency: CURRENCY_NAME - Status: STATUS - Block: BLOCK - From: SENDER - To: RECIPIENT - """ - - re_type = re.compile("Type: (Status)") - re_status = re.compile("Status: (NEW|NEW_BACK|UP|UP_BACK|DOWN)") - re_block = re.compile("Block: ([0-9]+-[0-9a-fA-F]{5,40})\n") - re_from = re.compile("From: ([1-9A-Za-z][^OIl]{42,45})\n") - re_to = re.compile("To: ([1-9A-Za-z][^OIl]{42,45})\n") - - def __init__(self, version, currency, status, blockid, sender, - recipient, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - - self.status = status - self.blockid = blockid - self.sender = sender - self.recipient = recipient - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Status.re_version.match(lines[n]).group(1)) - n = n + 1 - - Status.re_type.match(lines[n]).group(1) - n = n + 1 - - currency = Status.re_currency.match(lines[n]).group(1) - n = n + 1 - - status = Status.re_status.match(lines[n]).group(1) - n = n + 1 - - blockid = Status.re_block.match(lines[n]).group(1) - n = n + 1 - - sender = Status.re_from.match(lines[n]).group(1) - n = n + 1 - - recipient = Status.re_to.match(lines[n]).group(1) - n = n + 1 - - signature = Status.re_signature.match(lines[n]).group(1) - n = n + 1 - - return cls(version, currency, status, blockid, - sender, recipient, signature) - - def raw(self): - return """Version: {0} -Type: Status -Currency: {1} -Status: {2} -Block: {3} -From: {4} -To: {5} -""".format(self.version, self.currency, self.status, - self.blockid, self.sender, self.recipient) diff --git a/lib/ucoinpy/documents/transaction.py b/lib/ucoinpy/documents/transaction.py deleted file mode 100644 index 5f2f4e1333f64eb4ee3844d5012a0fcc092fe97a..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/documents/transaction.py +++ /dev/null @@ -1,299 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" - -from .document import Document -import re -import logging - - -class Transaction(Document): - """ -Document format : -Version: VERSION -Type: Transaction -Currency: CURRENCY_NAME -Issuers: -PUBLIC_KEY -... -Inputs: -INDEX:SOURCE:NUMBER:FINGERPRINT:AMOUNT -... -Outputs: -PUBLIC_KEY:AMOUNT -... -Comment: COMMENT -... - - -Compact format : -TX:VERSION:NB_ISSUERS:NB_INPUTS:NB_OUTPUTS:HAS_COMMENT -PUBLIC_KEY:INDEX -... -INDEX:SOURCE:FINGERPRINT:AMOUNT -... -PUBLIC_KEY:AMOUNT -... -COMMENT -SIGNATURE -... - """ - - re_type = re.compile("Type: (Transaction)\n") - re_header = re.compile("TX:([0-9]+):([0-9]+):([0-9]+):([0-9]+):(0|1)\n") - re_issuers = re.compile("Issuers:\n") - re_inputs = re.compile("Inputs:\n") - re_outputs = re.compile("Outputs:\n") - re_compact_comment = re.compile("([^\n]+)\n") - re_comment = re.compile("Comment: ([^\n]*)\n") - re_pubkey = re.compile("([1-9A-Za-z][^OIl]{42,45})\n") - - def __init__(self, version, currency, issuers, inputs, outputs, - comment, signatures): - """ - Constructor - """ - super().__init__(version, currency, signatures) - - self.issuers = issuers - self.inputs = inputs - self.outputs = outputs - self.comment = comment - - @classmethod - def from_compact(cls, currency, compact): - lines = compact.splitlines(True) - n = 0 - - header_data = Transaction.re_header.match(lines[n]) - version = int(header_data.group(1)) - issuers_num = int(header_data.group(2)) - inputs_num = int(header_data.group(3)) - outputs_num = int(header_data.group(4)) - has_comment = int(header_data.group(5)) - n = n + 1 - - issuers = [] - inputs = [] - outputs = [] - signatures = [] - for i in range(0, issuers_num): - issuer = Transaction.re_pubkey.match(lines[n]).group(1) - issuers.append(issuer) - n = n + 1 - - for i in range(0, inputs_num): - input_source = InputSource.from_inline(lines[n]) - inputs.append(input_source) - n = n + 1 - - for i in range(0, outputs_num): - output_source = OutputSource.from_inline(lines[n]) - outputs.append(output_source) - n = n + 1 - - comment = "" - if has_comment == 1: - comment = Transaction.re_compact_comment.match(lines[n]).group(1) - n = n + 1 - - while n < len(lines): - signatures.append(Transaction.re_signature.match(lines[n]).group(1)) - n = n + 1 - - return cls(version, currency, issuers, inputs, outputs, comment, signatures) - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Transaction.re_version.match(lines[n]).group(1)) - n = n + 1 - - Transaction.re_type.match(lines[n]).group(1) - n = n + 1 - - currency = Transaction.re_currency.match(lines[n]).group(1) - n = n + 1 - - issuers = [] - inputs = [] - outputs = [] - signatures = [] - - if Transaction.re_issuers.match(lines[n]): - n = n + 1 - while Transaction.re_inputs.match(lines[n]) is None: - issuer = Transaction.re_pubkey.match(lines[n]).group(1) - issuers.append(issuer) - n = n + 1 - - if Transaction.re_inputs.match(lines[n]): - n = n + 1 - while Transaction.re_outputs.match(lines[n]) is None: - input_source = InputSource.from_inline(lines[n]) - inputs.append(input_source) - n = n + 1 - - if Transaction.re_outputs.match(lines[n]) is not None: - n = n + 1 - while not Transaction.re_comment.match(lines[n]): - output = OutputSource.from_inline(lines[n]) - outputs.append(output) - n = n + 1 - - comment = Transaction.re_comment.match(lines[n]).group(1) - n = n + 1 - - if Transaction.re_signature.match(lines[n]) is not None: - while n < len(lines): - sign = Transaction.re_signature.match(lines[n]).group(1) - signatures.append(sign) - n = n + 1 - - return cls(version, currency, issuers, inputs, outputs, - comment, signatures) - - def raw(self): - doc = """Version: {0} -Type: Transaction -Currency: {1} -Issuers: -""".format(self.version, - self.currency) - - for p in self.issuers: - doc += "{0}\n".format(p) - - doc += "Inputs:\n" - for i in self.inputs: - doc += "{0}\n".format(i.inline()) - - doc += "Outputs:\n" - for o in self.outputs: - doc += "{0}\n".format(o.inline()) - - doc += "Comment: " - doc += "{0}\n".format(self.comment) - - return doc - - def compact(self): - """ - Return a transaction in its compact format. - """ - """TX:VERSION:NB_ISSUERS:NB_INPUTS:NB_OUTPUTS:HAS_COMMENT -PUBLIC_KEY:INDEX -... -INDEX:SOURCE:FINGERPRINT:AMOUNT -... -PUBLIC_KEY:AMOUNT -... -COMMENT -""" - doc = "TX:{0}:{1}:{2}:{3}:{4}\n".format(self.version, - len(self.issuers), - len(self.inputs), - len(self.outputs), - '1' if self.comment != "" else '0') - for pubkey in self.issuers: - doc += "{0}\n".format(pubkey) - for i in self.inputs: - doc += "{0}\n".format(i.compact()) - for o in self.outputs: - doc += "{0}\n".format(o.inline()) - if self.comment != "": - doc += "{0}\n".format(self.comment) - for s in self.signatures: - doc += "{0}\n".format(s) - - return doc - - -class SimpleTransaction(Transaction): - """ -As transaction class, but for only one issuer. -... - """ - def __init__(self, version, currency, issuer, - single_input, outputs, comment, signature): - """ - Constructor - """ - super().__init__(version, currency, [issuer], [single_input], - outputs, comment, [signature]) - - -class InputSource(): - """ - A Transaction INPUT - - Compact : - INDEX:SOURCE:FINGERPRINT:AMOUNT - """ - re_inline = re.compile("([0-9]+):(D|T):([0-9]+):\ -([0-9a-fA-F]{5,40}):([0-9]+)\n") - re_compact = re.compile("([0-9]+):(D|T):([0-9a-fA-F]{5,40}):([0-9]+)\n") - - def __init__(self, index, source, number, txhash, amount): - self.index = index - self.source = source - self.number = number - self.txhash = txhash - self.amount = amount - - @classmethod - def from_inline(cls, inline): - data = InputSource.re_inline.match(inline) - index = int(data.group(1)) - source = data.group(2) - number = int(data.group(3)) - txhash = data.group(4) - amount = int(data.group(5)) - return cls(index, source, number, txhash, amount) - - @classmethod - def from_bma(cls, bma_data): - index = None - source = bma_data['type'] - number = bma_data['number'] - txhash = bma_data['fingerprint'] - amount = bma_data['amount'] - return cls(index, source, number, txhash, amount) - - def inline(self): - return "{0}:{1}:{2}:{3}:{4}".format(self.index, - self.source, - self.number, - self.txhash, - self.amount) - - def compact(self): - return "{0}:{1}:{2}:{3}".format(self.index, - self.source, - self.txhash, - self.amount) - - -class OutputSource(): - """ - A Transaction OUTPUT - """ - re_inline = re.compile("([1-9A-Za-z][^OIl]{42,45}):([0-9]+)") - - def __init__(self, pubkey, amount): - self.pubkey = pubkey - self.amount = amount - - @classmethod - def from_inline(cls, inline): - data = OutputSource.re_inline.match(inline) - pubkey = data.group(1) - amount = int(data.group(2)) - return cls(pubkey, amount) - - def inline(self): - return "{0}:{1}".format(self.pubkey, self.amount) diff --git a/lib/ucoinpy/key/__init__.py b/lib/ucoinpy/key/__init__.py deleted file mode 100644 index f0813ef87b1962e027593dd312548c61d78c2f5d..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/key/__init__.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Ucoin public and private keys - -@author: inso -""" - -import base58 -import base64 -from pylibscrypt import scrypt -from libnacl.sign import Signer as NaclSigningKey - - -SEED_LENGTH = 32 # Length of the key -crypto_sign_BYTES = 64 -SCRYPT_PARAMS = {'N': 4096, - 'r': 16, - 'p': 1 - } - -def _ensure_bytes(data): - if isinstance(data, str): - return bytes(data, 'utf-8') - - return data - -class SigningKey(NaclSigningKey): - def __init__(self, salt, password): - salt = _ensure_bytes(salt) - password = _ensure_bytes(password) - seed = scrypt(password, salt, - SCRYPT_PARAMS['N'], SCRYPT_PARAMS['r'], SCRYPT_PARAMS['p'], - SEED_LENGTH) - - super().__init__(seed) - self.pubkey = Base58Encoder.encode(self.vk) - -class Base58Encoder(object): - @staticmethod - def encode(data): - return base58.b58encode(data) - - @staticmethod - def decode(data): - return base58.b58decode(data) diff --git a/lib/ucoinpy/key/hdwallet.py b/lib/ucoinpy/key/hdwallet.py deleted file mode 100644 index 1a135d7da916fb4155d1fb8116859ec753d2e91d..0000000000000000000000000000000000000000 --- a/lib/ucoinpy/key/hdwallet.py +++ /dev/null @@ -1,378 +0,0 @@ -""" -HD Wallet inspired from Bip32 wallets. - -@author: inso -""" -""" -import os -import hmac -import hashlib -import ed25519 -import struct -import base58 -import base64 - -from hashlib import sha256 -from ecdsa.curves import SECP256k1 -from ecdsa.ecdsa import int_to_string, string_to_int -from ecdsa.numbertheory import square_root_mod_prime as sqrt_mod - -MIN_ENTROPY_LEN = 128 # bits -HDWALLET_HARDENED = 0x80000000 # choose from hardened set of child keys -CURVE_GEN = ecdsa.ecdsa.generator_secp256k1 -CURVE_ORDER = CURVE_GEN.order() -FIELD_ORDER = SECP256k1.curve.p() -INFINITY = ecdsa.ellipticcurve.INFINITY - - -class HDWalletKey(object): - - # Static initializers to create from entropy or external formats - # - @staticmethod - def fromEntropy(entropy, public=False): - "Create a HDWallet using supplied entropy >= MIN_ENTROPY_LEN" - if entropy == None: - entropy = os.urandom(MIN_ENTROPY_LEN/8) # Python doesn't have os.random() - if not len(entropy) >= MIN_ENTROPY_LEN/8: - raise ValueError("Initial entropy %i must be at least %i bits" % - (len(entropy), MIN_ENTROPY_LEN)) - I = hmac.new("UCoin seed", entropy, hashlib.sha512).digest() - - Il, Ir = I[:32], I[32:] - # FIXME test Il for 0 or less than SECP256k1 prime field order - key = HDWalletKey(secret=Il, chain=Ir, depth=0, index=0, fpr='\0\0\0\0', public=False) - if public: - key.SetPublic() - return key - - @staticmethod - def fromExtendedKey(xkey, public=False): - """ - Create a HDWallet by importing from extended private or public key string - - If public is True, return a public-only key regardless of input type. - """ - # Sanity checks - raw = base58.b58decode_check(xkey) - # To fix - #if len(raw) != 78: - # raise ValueError("extended key format wrong length") - - # Verify address version/type - #version = raw[:4] - #if version == EX_MAIN_PRIVATE: - # raise ValueError("unknown extended key version") - - # Extract remaining fields - depth = ord(raw[4]) - fpr = raw[5:9] - child = struct.unpack(">L", raw[9:13])[0] - chain = raw[13:45] - secret = raw[45:78] - - # Extract private key or public key point - if keytype == 'xprv': - secret = secret[1:] - else: - # Recover public curve point from compressed key - lsb = ord(secret[0]) & 1 - x = string_to_int(secret[1:]) - ys = (x**3+7) % FIELD_ORDER # y^2 = x^3 + 7 mod p - y = sqrt_mod(ys, FIELD_ORDER) - if y & 1 != lsb: - y = FIELD_ORDER-y - point = ecdsa.ellipticcurve.Point(SECP256k1.curve, x, y) - secret = ecdsa.VerifyingKey.from_public_point(point, curve=SECP256k1) - - is_pubkey = (keytype == 'xpub') - key = HDWalletKey(secret=secret, chain=chain, depth=depth, index=child, - fpr=fpr, public=is_pubkey) - if not is_pubkey and public: - key = key.SetPublic() - return key - - - # Normal class initializer - def __init__(self, secret, chain, depth, index, fpr, public=False): - """ - Create a public or private BIP32Key using key material and chain code. - - secret This is the source material to generate the keypair, either a - 32-byte string representation of a private key, or the ECDSA - library object representing a public key. - - chain This is a 32-byte string representation of the chain code - - depth Child depth; parent increments its own by one when assigning this - - index Child index - - fpr Parent fingerprint - - public If true, this keypair will only contain a public key and can only create - a public key chain. - """ - - self.public = public - if public is False: - self.k = ed25519.SigningKey(base58.b58decode(secret)) - self.K = self.k.get_verifying_key() - else: - self.k = None - self.K = secret - - self.C = chain - self.depth = depth - self.index = index - self.parent_fpr = fpr - - # Internal methods not intended to be called externally - def _hmac(self, data): - """ - Calculate the HMAC-SHA512 of input data using the chain code as key. - - Returns a tuple of the left and right halves of the HMAC - """ - I = hmac.new(self.C, data, hashlib.sha512).digest() - return (I[:32], I[32:]) - - def _CKDpriv(self, i): - """ - Create a child key of index 'i'. - - If the most significant bit of 'i' is set, then select from the - hardened key set, otherwise, select a regular child key. - - Returns a BIP32Key constructed with the child key parameters, - or None if i index would result in an invalid key. - """ - # Index as bytes, BE - i_str = struct.pack(">L", i) - - # Data to HMAC - if i & HDWALLET_HARDENED: - data = b'\0' + self.k.to_string() + i_str - else: - data = self.PublicKey() + i_str - # Get HMAC of data - (Il, Ir) = self._hmac(data) - - # Construct new key material from Il and current private key - Il_int = string_to_int(Il) - if Il_int > CURVE_ORDER: - return None - pvt_int = string_to_int(self.k.to_string()) - k_int = (Il_int + pvt_int) % CURVE_ORDER - if (k_int == 0): - return None - secret = (b'\0'*32 + int_to_string(k_int))[-32:] - - # Construct and return a new BIP32Key - return HDWalletKey(secret=secret, chain=Ir, depth=self.depth+1, - index=i, fpr=self.Fingerprint(), public=False) - - def _CKDpub(self, i): - """ - Create a publicly derived child key of index 'i'. - - If the most significant bit of 'i' is set, this is - an error. - - Returns a HDWalletKey constructed with the child key parameters, - or None if index would result in invalid key. - """ - - if i & HDWALLET_HARDENED: - raise Exception("Cannot create a hardened child key using public child derivation") - - # Data to HMAC. Same as CKDpriv() for public child key. - data = self.PublicKey() + struct.pack(">L", i) - - # Get HMAC of data - (Il, Ir) = self.hmac(data) - - # Construct curve point Il*G+K - Il_int = string_to_int(Il) - if Il_int >= CURVE_ORDER: - return None - point = Il_int*CURVE_GEN + self.K.pubkey.point - if point == INFINITY: - return None - - # Retrieve public key based on curve point - K_i = ed25519.VerifyingKey.from_public_point(point, curve=SECP256k1) - - # Construct and return a new BIP32Key - return HDWalletKey(secret=K_i, chain=Ir, depth=self.depth, index=i, fpr=self.Fingerprint(), public=True) - - - # Public methods - # - def ChildKey(self, i): - """ - Create and return a child key of this one at index 'i'. - - The index 'i' should be summed with BIP32_HARDEN to indicate - to use the private derivation algorithm. - """ - if self.public is False: - return self.CKDpriv(i) - else: - return self.CKDpub(i) - - - def SetPublic(self): - "Convert a private BIP32Key into a public one" - self.k = None - self.public = True - - - def PrivateKey(self): - "Return private key as string" - if self.public: - raise Exception("Publicly derived deterministic keys have no private half") - else: - return self.k.to_string() - - - def PublicKey(self): - "Return compressed public key encoding" - if self.K.pubkey.point.y() & 1: - ck = b'\3'+int_to_string(self.K.pubkey.point.x()) - else: - ck = b'\2'+int_to_string(self.K.pubkey.point.x()) - return ck - - - def ChainCode(self): - "Return chain code as string" - return self.C - - - def Identifier(self): - "Return key identifier as string" - cK = self.PublicKey() - return hashlib.new('ripemd160', sha256(cK).digest()).digest() - - - def Fingerprint(self): - "Return key fingerprint as string" - return self.Identifier()[:4] - - - def Address(self): - "Return compressed public key address" - vh160 = '\x00'+self.Identifier() - return Base58.check_encode(vh160) - - - def WalletImportFormat(self): - "Returns private key encoded for wallet import" - if self.public: - raise Exception("Publicly derived deterministic keys have no private half") - raw = '\x80' + self.k.to_string() + '\x01' # Always compressed - return Base58.check_encode(raw) - - - def ExtendedKey(self, private=True, encoded=True): - "Return extended private or public key as string, optionally Base58 encoded" - if self.public is True and private is True: - raise Exception("Cannot export an extended private key from a public-only deterministic key") - version = EX_MAIN_PRIVATE if private else EX_MAIN_PUBLIC - depth = chr(self.depth) - fpr = self.parent_fpr - child = struct.pack('>L', self.index) - chain = self.C - if self.public is True or private is False: - data = self.PublicKey() - else: - data = '\x00' + self.PrivateKey() - raw = version+depth+fpr+child+chain+data - if not encoded: - return raw - else: - return Base58.check_encode(raw) - - # Debugging methods - # - def dump(self): - "Dump key fields mimicking the BIP0032 test vector format" - print " * Identifier" - print " * (hex): ", self.Identifier().encode('hex') - print " * (fpr): ", self.Fingerprint().encode('hex') - print " * (main addr):", self.Address() - if self.public is False: - print " * Secret key" - print " * (hex): ", self.PrivateKey().encode('hex') - print " * (wif): ", self.WalletImportFormat() - print " * Public key" - print " * (hex): ", self.PublicKey().encode('hex') - print " * Chain code" - print " * (hex): ", self.C.encode('hex') - print " * Serialized" - print " * (pub hex): ", self.ExtendedKey(private=False, encoded=False).encode('hex') - print " * (prv hex): ", self.ExtendedKey(private=True, encoded=False).encode('hex') - print " * (pub b58): ", self.ExtendedKey(private=False, encoded=True) - print " * (prv b58): ", self.ExtendedKey(private=True, encoded=True) - - -if __name__ == "__main__": - import sys - - # BIP0032 Test vector 1 - entropy='000102030405060708090A0B0C0D0E0F'.decode('hex') - m = BIP32Key.fromEntropy(entropy) - print "Test vector 1:" - print "Master (hex):", entropy.encode('hex') - print "* [Chain m]" - m.dump() - - print "* [Chain m/0h]" - m = m.ChildKey(0+BIP32_HARDEN) - m.dump() - - print "* [Chain m/0h/1]" - m = m.ChildKey(1) - m.dump() - - print "* [Chain m/0h/1/2h]" - m = m.ChildKey(2+BIP32_HARDEN) - m.dump() - - print "* [Chain m/0h/1/2h/2]" - m = m.ChildKey(2) - m.dump() - - print "* [Chain m/0h/1/2h/2/1000000000]" - m = m.ChildKey(1000000000) - m.dump() - - # BIP0032 Test vector 2 - entropy = 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'.decode('hex') - m = BIP32Key.fromEntropy(entropy) - print "Test vector 2:" - print "Master (hex):", entropy.encode('hex') - print "* [Chain m]" - m.dump() - - print "* [Chain m/0]" - m = m.ChildKey(0) - m.dump() - - print "* [Chain m/0/2147483647h]" - m = m.ChildKey(2147483647+BIP32_HARDEN) - m.dump() - - print "* [Chain m/0/2147483647h/1]" - m = m.ChildKey(1) - m.dump() - - print "* [Chain m/0/2147483647h/1/2147483646h]" - m = m.ChildKey(2147483646+BIP32_HARDEN) - m.dump() - - print "* [Chain m/0/2147483647h/1/2147483646h/2]" - m = m.ChildKey(2) - m.dump() -""" \ No newline at end of file