diff --git a/.travis.yml b/.travis.yml index bb314967a284f91bc769d49611e766a54449d04e..40f3f5c26a9228afdc3968e7772d0b36b4e36d3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,6 @@ install: - pip install -r requirements.txt # command to run tests script: - - coverage run --source=ucoinpy setup.py test + - coverage run --source=duniterpy setup.py test after_success: - coveralls \ No newline at end of file diff --git a/README.md b/README.md index 19ca75eaffc8280a5bc76544b7059b5ebadd85da..c62aa5b0e57a2ee3fde6c57ea92c91eaf4575e86 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -#ucoin-python-api -[](https://travis-ci.org/ucoin-io/ucoin-python-api) [](https://coveralls.io/github/ucoin-io/ucoin-python-api?branch=master) +#duniter-python-api +[](https://travis-ci.org/duniter-io/duniter-python-api) [](https://coveralls.io/github/duniter-io/duniter-python-api?branch=master) -A python implementation of [uCoin](https://github.com/ucoin-io/ucoin) API +A python implementation of [duniter](https://github.com/duniter-io/duniter) API ## Features - * Supports uCoin's Basic Merkle Api + * Supports duniter's Basic Merkle Api * Asynchronous - * uCoin signing key + * duniter signing key ## Requirements * Python >= 3.5 @@ -16,7 +16,7 @@ A python implementation of [uCoin](https://github.com/ucoin-io/ucoin) API * [base58](https://pypi.python.org/pypi/base58 "base58") ##Installation -You can install ucoin-python-api and all its dependencies via the following pip install : -`pip install ucoinpy` +You can install duniter-python-api and all its dependencies via the following pip install : +`pip install duniterpy` -Please take a look at the document [HTTP API](https://github.com/ucoin-io/ucoin/blob/master/doc/HTTP_API.md) to learn about the API. +Please take a look at the document [HTTP API](https://github.com/duniter-io/duniter/blob/master/doc/HTTP_API.md) to learn about the API. diff --git a/docs/Makefile b/docs/Makefile index 705701a98b67e27204eabcc2ae35dcaef16544c2..a4db4d8965d255fb4547e3a0d35b714b983b800c 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -87,9 +87,9 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ucoinpy.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/duniterpy.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ucoinpy.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/duniterpy.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @@ -104,8 +104,8 @@ devhelp: @echo @echo "Build finished." @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/ucoinpy" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ucoinpy" + @echo "# mkdir -p $$HOME/.local/share/devhelp/duniterpy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/duniterpy" @echo "# devhelp" epub: diff --git a/docs/conf.py b/docs/conf.py index f8abe0917dc574b97c9483ddcb01cbd93e24d785..8213b7e27e45886aed4af8f7762c80a0f5744ff5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# ucoinpy documentation build configuration file, created by +# duniterpy documentation build configuration file, created by # sphinx-quickstart on Tue Oct 6 16:34:46 2015. # # This file is execfile()d with the current directory set to its @@ -62,7 +62,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'ucoinpy' +project = 'duniterpy' copyright = '2015, caner & inso' author = 'caner & inso' @@ -216,7 +216,7 @@ html_static_path = ['_static'] #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'ucoinpydoc' +htmlhelp_basename = 'duniterpydoc' # -- Options for LaTeX output --------------------------------------------- @@ -238,7 +238,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'ucoinpy.tex', 'ucoinpy Documentation', + (master_doc, 'duniterpy.tex', 'duniterpy Documentation', 'caner \\& inso', 'manual'), ] @@ -268,7 +268,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'ucoinpy', 'ucoinpy Documentation', + (master_doc, 'duniterpy', 'duniterpy Documentation', [author], 1) ] @@ -282,8 +282,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'ucoinpy', 'ucoinpy Documentation', - author, 'ucoinpy', 'One line description of project.', + (master_doc, 'duniterpy', 'duniterpy Documentation', + author, 'duniterpy', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/documents.rst b/docs/documents.rst index b37d6313f76a9b86b3159cd3fe72177340c98458..4c248c8b73ac7d132b46bbdef6027ba112a901f2 100644 --- a/docs/documents.rst +++ b/docs/documents.rst @@ -1,37 +1,37 @@ Documents methods ================= -.. automodule:: ucoinpy.documents.block +.. automodule:: duniterpy.documents.block :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.certification +.. automodule:: duniterpy.documents.certification :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.document +.. automodule:: duniterpy.documents.document :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.membership +.. automodule:: duniterpy.documents.membership :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.peer +.. automodule:: duniterpy.documents.peer :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.status +.. automodule:: duniterpy.documents.status :members: :special-members: :exclude-members: __dict__,__weakref__ -.. automodule:: ucoinpy.documents.transaction +.. automodule:: duniterpy.documents.transaction :members: :special-members: :exclude-members: __dict__,__weakref__ \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index eafdb1e7b105449eaefbe25a8f1bbf672a41dbf8..f2bf96f1d1754492ca424376d3210e5739693b1b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,28 +1,28 @@ -.. ucoinpy documentation master file, created by +.. duniterpy documentation master file, created by sphinx-quickstart on Tue Oct 6 16:34:46 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -ucoinpy : A python implementation of uCoin API +duniterpy : A python implementation of duniter API ============================================== -ucoinpy is a library to develop an application for uCoin. -ucoinpy helps to handle the following problem : -* Request Basic Merkle API provided by ucoin nodes +duniterpy is a library to develop an application for duniter. +duniterpy helps to handle the following problem : +* Request Basic Merkle API provided by duniter nodes * Request nodes in a non-blocking way -* Handle ucoin signing keys +* Handle duniter signing keys Installation ------------ Simply type:: - $ pip install ucoinpy + $ pip install duniterpy Source code ----------- -Sources can be found at https://github.com/ucoin-io/ucoin-python-api +Sources can be found at https://github.com/duniter-io/duniter-python-api Contributions are welcome. diff --git a/docs/make.bat b/docs/make.bat index 7b002b3e97749255fecf4f96c261e925eb8f962f..e334c012c7fe02782a22a19aec562ce359dd31da 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -127,9 +127,9 @@ if "%1" == "qthelp" ( echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ucoinpy.qhcp + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\duniterpy.qhcp echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ucoinpy.ghc + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\duniterpy.ghc goto end ) diff --git a/setup.py b/setup.py index 5bc6c31aef9af447a05342a7ec28709c32e38dee..4b7f4b676c43c045d22ec7baf0562c98214e5ea5 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ from setuptools import setup, find_packages -import ucoinpy +import duniterpy import os import re @@ -39,9 +39,9 @@ for requirement in (l.strip() for l in open('requirements.txt')): install_requires.append(requirement) setup( - name='ucoinpy', + name='duniterpy', - version=ucoinpy.__version__, + version=duniterpy.__version__, packages=find_packages(), @@ -49,13 +49,13 @@ setup( author_email="insomniak.fr@gmail.com", - description="A python implementation of [uCoin](https://github.com/ucoin-io/ucoin) API", + description="A python implementation of [duniter](https://github.com/duniter-io/duniter) API", long_description=open('README.md').read(), # Active la prise en compte du fichier MANIFEST.in include_package_data=True, - url='https://github.com/ucoin-io/ucoin-python-api', + url='https://github.com/duniter-io/duniter-python-api', test_suite="tests", classifiers=[ diff --git a/tests/api/bma/test_blockchain.py b/tests/api/bma/test_blockchain.py index ba19ed94f7478b1300c7673b26531ee06223ecd6..d04eebdeca99fb3673d3ac0fefc588904cc87383 100644 --- a/tests/api/bma/test_blockchain.py +++ b/tests/api/bma/test_blockchain.py @@ -2,7 +2,7 @@ import unittest import jsonschema import aiohttp from tests.api.webserver import WebFunctionalSetupMixin, web, asyncio -from ucoinpy.api.bma.blockchain import Parameters, Block, Current, Hardship, Membership, Newcomers, \ +from duniterpy.api.bma.blockchain import Parameters, Block, Current, Hardship, Membership, Newcomers, \ Certifications, Joiners, Actives, Leavers, UD, TX diff --git a/tests/api/bma/test_network.py b/tests/api/bma/test_network.py index 24282b27b328cfabc66081bb8b52929181a7d4cb..9251d2dcec4eb675763cfce8e6b432831831fad8 100644 --- a/tests/api/bma/test_network.py +++ b/tests/api/bma/test_network.py @@ -1,8 +1,8 @@ import unittest import jsonschema -from ucoinpy.api.bma.network import Peering +from duniterpy.api.bma.network import Peering from tests.api.webserver import WebFunctionalSetupMixin, web, asyncio -from ucoinpy.api.bma.network.peering import Peers +from duniterpy.api.bma.network.peering import Peers class Test_BMA_Network(WebFunctionalSetupMixin, unittest.TestCase): diff --git a/tests/api/bma/test_tx.py b/tests/api/bma/test_tx.py index 54483c992c795a822f7effdb21eee1f18c019372..a1a6a3d2c9ef8fa759a3bbe1b2ce943f794079e4 100644 --- a/tests/api/bma/test_tx.py +++ b/tests/api/bma/test_tx.py @@ -1,9 +1,9 @@ import unittest import jsonschema import aiohttp -from ucoinpy.api.bma.tx import History, Sources +from duniterpy.api.bma.tx import History, Sources from tests.api.webserver import WebFunctionalSetupMixin, web, asyncio -from ucoinpy.api.bma.tx.history import Blocks +from duniterpy.api.bma.tx.history import Blocks class Test_BMA_TX(WebFunctionalSetupMixin, unittest.TestCase): diff --git a/tests/api/bma/test_wot.py b/tests/api/bma/test_wot.py index 845c4e27ecf9e40546d5b4e9abcf9aed2b7c8dc3..a41fd27d59768f33c03b42ecaf925886e70e5a56 100644 --- a/tests/api/bma/test_wot.py +++ b/tests/api/bma/test_wot.py @@ -3,7 +3,7 @@ import unittest import jsonschema import json from tests.api.webserver import WebFunctionalSetupMixin, web, asyncio -from ucoinpy.api.bma.wot import Lookup, Members, CertifiedBy, CertifiersOf +from duniterpy.api.bma.wot import Lookup, Members, CertifiedBy, CertifiersOf class Test_BMA_Wot(WebFunctionalSetupMixin, unittest.TestCase): diff --git a/tests/api/bma/test_ws.py b/tests/api/bma/test_ws.py index dfad2a78ed82078bbb53f5f97145288005fae02c..136691a08bb3640cbb1fce85dc00302e98853037 100644 --- a/tests/api/bma/test_ws.py +++ b/tests/api/bma/test_ws.py @@ -1,6 +1,6 @@ import unittest from tests.api.webserver import WebFunctionalSetupMixin -from ucoinpy.api.bma.ws import Block, Peer +from duniterpy.api.bma.ws import Block, Peer class Test_BMA_Websocket(WebFunctionalSetupMixin, unittest.TestCase): diff --git a/tests/api/test_bma.py b/tests/api/test_bma.py index c3a0f2b1e2c73a6b5af822eaec45fc87aaa51849..454f469a7dfcfcf5e57d36027e394c7f18d102bc 100644 --- a/tests/api/test_bma.py +++ b/tests/api/test_bma.py @@ -1,6 +1,6 @@ import unittest -from ucoinpy.api.bma import API -from ucoinpy.documents.peer import BMAEndpoint +from duniterpy.api.bma import API +from duniterpy.documents.peer import BMAEndpoint class Test_BMA_API(unittest.TestCase): diff --git a/tests/documents/test_block.py b/tests/documents/test_block.py index bee4330078fce2734e7729a52d6235d165fdd0e2..99533d89f813e63e5de5b6ea0c4d8bd3245eb2dc 100644 --- a/tests/documents/test_block.py +++ b/tests/documents/test_block.py @@ -4,7 +4,7 @@ Created on 12 déc. 2014 @author: inso ''' import unittest -from ucoinpy.documents.block import Block, BlockUID +from duniterpy.documents.block import Block, BlockUID raw_block = """Version: 2 Type: Block diff --git a/tests/documents/test_certification.py b/tests/documents/test_certification.py index c89668df9a9cf20b1f5e6c871dcac3c5dc0e3b96..25d97c2bbb1637c87088fed52dccc35388a05831 100644 --- a/tests/documents/test_certification.py +++ b/tests/documents/test_certification.py @@ -5,8 +5,8 @@ Created on 6 déc. 2014 ''' import unittest -from ucoinpy.documents.certification import SelfCertification, Certification, Revokation -from ucoinpy.documents import Block, BlockUID +from duniterpy.documents.certification import SelfCertification, Certification, Revokation +from duniterpy.documents import Block, BlockUID selfcert_inlines = ["HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:\ h/H8tDIEbfA4yxMQcvfOXVDQhi1sUa9qYtPKrM59Bulv97ouwbAvAsEkC1Uyit1IOpeAV+CQQs4IaAyjE8F1Cw==:\ diff --git a/tests/documents/test_membership.py b/tests/documents/test_membership.py index 4402258c09c479ebf2ac6e2f94117c982d08ba87..4c2fe1f150d7acb90a57d07b6d674298526049f3 100644 --- a/tests/documents/test_membership.py +++ b/tests/documents/test_membership.py @@ -4,7 +4,7 @@ Created on 12 déc. 2014 @author: inso ''' import unittest -from ucoinpy.documents.membership import Membership +from duniterpy.documents.membership import Membership membership_inline = "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:\ dkaXIiCYUJtCg8Feh/BKvPYf4uFH9CJ/zY6J4MlA9BsjmcMe4YAblvNt/gJy31b1aGq3ue3h14mLMCu84rraDg==:\ diff --git a/tests/documents/test_peer.py b/tests/documents/test_peer.py index 19df5754d65faeea95fbe37673081faf00a1e21e..f67f04b619028c44887c2de7335d13c6ae0c56df 100644 --- a/tests/documents/test_peer.py +++ b/tests/documents/test_peer.py @@ -4,7 +4,7 @@ Created on 13 déc. 2014 @author: inso ''' import unittest -from ucoinpy.documents.peer import Peer, BMAEndpoint, UnknownEndpoint +from duniterpy.documents.peer import Peer, BMAEndpoint, UnknownEndpoint rawpeer = """Version: 2 diff --git a/tests/documents/test_transaction.py b/tests/documents/test_transaction.py index cfb7166ebc7b3bcc8ba6edf0c674aa14c2017e0e..a80cbc3553b5ab1d95bdf2461412845267131515 100644 --- a/tests/documents/test_transaction.py +++ b/tests/documents/test_transaction.py @@ -5,8 +5,8 @@ Created on 12 déc. 2014 ''' import unittest import pypeg2 -from ucoinpy.grammars import output -from ucoinpy.documents.transaction import Transaction, reduce_base, SimpleTransaction +from duniterpy.grammars import output +from duniterpy.documents.transaction import Transaction, reduce_base, SimpleTransaction tx_compact = """TX:2:3:6:6:3:1:0 diff --git a/tests/grammars/test_output.py b/tests/grammars/test_output.py index 6f43bdf3b264a22c9dafdb308782f054d79c2151..f6835060428a4abb95c21cd38274c6a7fe24b376 100644 --- a/tests/grammars/test_output.py +++ b/tests/grammars/test_output.py @@ -1,4 +1,4 @@ -from ucoinpy.grammars import output +from duniterpy.grammars import output import unittest import pypeg2 diff --git a/ucoinpy/__init__.py b/ucoinpy/__init__.py deleted file mode 100644 index 75d6b3b044cbddaed4a9c27fd85431096fe88c1a..0000000000000000000000000000000000000000 --- a/ucoinpy/__init__.py +++ /dev/null @@ -1,27 +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"] - -__author__ = 'Caner Candan & inso' -__version__ = '0.20.1dev5' -__nonsense__ = 'uCoin' - -from . import api, documents, key \ No newline at end of file diff --git a/ucoinpy/api/__init__.py b/ucoinpy/api/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/ucoinpy/api/bma/__init__.py b/ucoinpy/api/bma/__init__.py deleted file mode 100644 index 67f0e2d76d26789f74cafc57926561d91a07c557..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/__init__.py +++ /dev/null @@ -1,30 +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 -# Inso <insomniak.fr at gmail.com> - - -__all__ = ['api'] - -PROTOCOL_VERSION = 2 - -import logging - -logger = logging.getLogger("ucoin") - - -from .api import API, ConnectionHandler -from . import network, blockchain, tx, wot, node, ud, ws \ No newline at end of file diff --git a/ucoinpy/api/bma/api.py b/ucoinpy/api/bma/api.py deleted file mode 100644 index 143b7f261bc15a7a2db0a773b26e0cc7190f804b..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/api.py +++ /dev/null @@ -1,199 +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 -# Inso <insomniak.fr at gmail.com> - - -import aiohttp, json, logging, jsonschema - -from ..errors import UcoinError - -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.""" - - error_schema = { - "type": "object", - "properties": { - "ucode": { - "type": "number" - }, - "message": { - "type": "string" - } - }, - "required": ["ucode", "message"] - } - - 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, scheme, 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 = '{scheme}://{server}:{port}/{module}'.format(scheme=scheme, - server=server, - port=port, - module=self.module) - return url + path - - def get(self, session, **kwargs): - """wrapper of overloaded __get__ method.""" - - return self.__get__(session, **kwargs) - - def post(self, session, **kwargs): - """wrapper of overloaded __post__ method.""" - - logger.debug('do some work with') - - data = self.__post__(session, **kwargs) - - logger.debug('and send back') - - return data - - async def __get__(self, session, **kwargs): - """interface purpose for GET request""" - pass - - async def __post__(self, session, **kwargs): - """interface purpose for POST request""" - pass - - def parse_text(self, text): - """ - Validate and parse the BMA answer from websocket - - :param str text: the bma answer - :return: the json data - """ - try: - data = json.loads(text) - jsonschema.validate(data, self.schema) - return data - except TypeError: - raise jsonschema.ValidationError("Could not parse json") - - def parse_error(self, text): - """ - Validate and parse the BMA answer from websocket - - :param str text: the bma error - :return: the json data - """ - try: - data = json.loads(text) - jsonschema.validate(data, self.error_schema) - return data - except TypeError: - raise jsonschema.ValidationError("Could not parse json") - - async def parse_response(self, response): - """ - Validate and parse the BMA answer - - :param response: - :return: the json data - """ - try: - data = await response.json() - jsonschema.validate(data, self.schema) - return data - except TypeError: - raise jsonschema.ValidationError("Could not parse json") - - async def requests_get(self, session, path, **kwargs): - """ - Requests GET wrapper in order to use API parameters. - - :params aiohttp.ClientSession session: the client session - :params str path: the request path - """ - logging.debug("Request : {0}".format(self.reverse_url("http", path))) - with aiohttp.Timeout(15): - response = await session.get(self.reverse_url("http", path), params=kwargs,headers=self.headers) - if response.status != 200: - try: - error_data = self.parse_error(await response.text()) - raise UcoinError(error_data) - except TypeError: - raise ValueError('status code != 200 => %d (%s)' % (response.status, (await response.text()))) - - return response - - async def requests_post(self, session, path, **kwargs): - """ - Requests POST wrapper in order to use API parameters. - - :param aiohttp.ClientSession session: the request session - :param str path: the request path - """ - if 'self_' in kwargs: - kwargs['self'] = kwargs.pop('self_') - - logging.debug("POST : {0}".format(kwargs)) - with aiohttp.Timeout(15): - response = await session.post(self.reverse_url("http", path), data=kwargs, headers=self.headers) - return response - - def connect_ws(self, session, path): - """ - Connect to a websocket in order to use API parameters - - :param aiohttp.ClientSession session: the session of the connection - :param str path: the url path - :return: - """ - url = self.reverse_url("ws", path) - return session.ws_connect(url) diff --git a/ucoinpy/api/bma/blockchain.py b/ucoinpy/api/bma/blockchain.py deleted file mode 100644 index 8c70db3d032f46acd6ae442ba90ac0ae31ac960a..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/blockchain.py +++ /dev/null @@ -1,453 +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 ucoinpy.api.bma 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.""" - schema = { - "type": "object", - "properties": - { - "currency": { - "type": "string" - }, - "c": { - "type": "number" - }, - "dt": { - "type": "number" - }, - "ud0": { - "type": "number" - }, - "sigPeriod": { - "type": "number" - }, - "sigStock": { - "type": "number" - }, - "sigWindow": { - "type": "number" - }, - "sigValidity": { - "type": "number" - }, - "sigQty": { - "type": "number" - }, - "xpercent": { - "type": "number" - }, - "msValidity": { - "type": "number" - }, - "stepMax": { - "type": "number" - }, - "medianTimeBlocks": { - "type": "number" - }, - "avgGenTime": { - "type": "number" - }, - "dtDiffEval": { - "type": "number" - }, - "blocksRot": { - "type": "number" - }, - "percentRot": { - "type": "number" - }, - }, - "required": ["currency", "c", "dt", "ud0","sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock", - "sigWindow", "msValidity","stepMax", "medianTimeBlocks", - "avgGenTime", "dtDiffEval", "blocksRot", "percentRot"] - } - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/parameters', **kwargs) - return (await self.parse_response(r)) - - -class Membership(Blockchain): - """GET/POST a Membership document.""" - schema = { - "type": "object", - "properties": - { - "pubkey": { - "type": "string" - }, - "uid": { - "type": "string", - }, - "sigDate": { - "type": "string" - }, - "memberships": { - "type": "array", - "items": { - "type": "object", - "properties": { - "version": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "membership": { - "type": "string" - }, - "blockNumber": { - "type": "number" - }, - "written": { - "type": ["number", "null"] - } - }, - "required": ["version", "currency", "membership", "blockNumber", "blockHash", "written"] - } - } - }, - "required": ["pubkey", "uid", "sigDate", "memberships"] - } - - def __init__(self, connection_handler, search=None): - super().__init__(connection_handler) - self.search = search - - async def __post__(self, session, **kwargs): - assert 'membership' in kwargs - - r = await self.requests_post(session, '/membership', **kwargs) - return r - - async def __get__(self, session, **kwargs): - assert self.search is not None - r = await self.requests_get(session, '/memberships/%s' % self.search, **kwargs) - return (await self.parse_response(r)) - - -class Block(Blockchain): - """GET/POST a block from/to the blockchain.""" - - schema = { - "type": "object", - "properties": { - "version": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "nonce": { - "type": "number" - }, - "number": { - "type": "number" - }, - "time": { - "type": "number" - }, - "medianTime": { - "type": "number" - }, - "dividend": { - "type": ["number", "null"] - }, - "monetaryMass": { - "type": ["number", "null"] - }, - "issuer": { - "type": "string" - }, - "previousHash": { - "type": ["string", "null"] - }, - "previousIssuer": { - "type": ["string", "null"] - }, - "membersCount": { - "type": "number" - }, - "hash": { - "type": "string" - }, - "inner_hash": { - "type": "string" - }, - "identities": { - "type": "array", - "items": { - "type": "string" - } - }, - "joiners": { - "type": "array", - "items": { - "type": "string" - } - }, - "leavers": { - "type": "array", - "items": { - "type": "string" - } - }, - "revoked": { - "type": "array", - "items": { - "type": "string" - } - }, - "excluded": { - "type": "array", - "items": { - "type": "string" - } - }, - "certifications": { - "type": "array", - "items": { - "type": "string" - } - }, - "transactions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "signatures": { - "type": "array" - }, - "version": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "issuers": { - "type": "array", - "items": { - "type": "string" - } - }, - "inputs": { - "type": "array", - "items": { - "type": "string" - } - }, - "unlocks": { - "type": "array", - "items": { - "type": "string" - } - }, - "outputs": { - "type": "array", - "item": { - "type": "string" - } - } - }, - "required": ["signatures", "version", "currency", "issuers", "inputs", "outputs"] - } - }, - "signature": { - "type": "string" - }, - }, - "required": ["version", "currency", "nonce", "number", "time", "medianTime", "dividend", "monetaryMass", - "issuer", "previousHash", "previousIssuer", "membersCount", "hash", "inner_hash", "identities", - "joiners", "leavers", "excluded", "certifications", "transactions", "signature"] - } - - 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 - - async def __get__(self, session, **kwargs): - assert self.number is not None - r = await self.requests_get(session, '/block/%d' % self.number, **kwargs) - return (await self.parse_response(r)) - - async def __post__(self, session, **kwargs): - assert 'block' in kwargs - assert 'signature' in kwargs - - r = await self.requests_post(session, '/block', **kwargs) - return r - - -class Current(Blockchain): - """GET, same as block/[number], but return last accepted block.""" - - schema = Block.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/current', **kwargs) - return (await self.parse_response(r)) - - -class Hardship(Blockchain): - """GET hardship level for given member's fingerprint for writing next block.""" - schema = { - "type": "object", - "properties": { - "block": { - "type": "number" - }, - "level": { - "type": "number" - } - }, - "required": ["block", "level"] - } - - 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 - - async def __get__(self, session, **kwargs): - assert self.fingerprint is not None - r = await self.requests_get(session, '/hardship/%s' % self.fingerprint.upper(), **kwargs) - return (await self.parse_response(r)) - - -class Newcomers(Blockchain): - """GET, return block numbers containing newcomers.""" - - schema = { - "type": "object", - "properties": { - "result":{ - "type": "object", - "properties": { - "blocks": { - "type": "array", - "items": { - "type": "number" - } - }, - }, - "required": ["blocks"] - } - }, - "required": ["result"] - } - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/newcomers', **kwargs) - return await self.parse_response(r) - - -class Certifications(Blockchain): - """GET, return block numbers containing certifications.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/certs', **kwargs) - return await self.parse_response(r) - - -class Joiners(Blockchain): - """GET, return block numbers containing joiners.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/joiners', **kwargs) - return await self.parse_response(r) - - -class Actives(Blockchain): - """GET, return block numbers containing actives.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/actives', **kwargs) - return await self.parse_response(r) - - -class Leavers(Blockchain): - """GET, return block numbers containing leavers.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/leavers', **kwargs) - return await self.parse_response(r) - - -class Excluded(Blockchain): - """GET, return block numbers containing excluded.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/excluded', **kwargs) - return await self.parse_response(r) - - -class UD(Blockchain): - """GET, return block numbers containing universal dividend.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/ud', **kwargs) - return await self.parse_response(r) - - -class TX(Blockchain): - """GET, return block numbers containing transactions.""" - - schema = Newcomers.schema - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/with/tx', **kwargs) - return await self.parse_response(r) diff --git a/ucoinpy/api/bma/network/__init__.py b/ucoinpy/api/bma/network/__init__.py deleted file mode 100644 index e2986776a6c978322289a5ee41ad49aad5515034..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/network/__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, 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.""" - schema = { - "type": "object", - "properties": { - "version": { - "type": ["number", "string"] - }, - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "endpoints": { - "type": "array", - "items": { - "type": "string" - } - }, - "signature": { - "type": "string" - } - }, - "required": ["version", "currency", "pubkey", "endpoints", "signature"] - } - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/peering', **kwargs) - return (await self.parse_response(r)) - -from . import peering diff --git a/ucoinpy/api/bma/network/peering.py b/ucoinpy/api/bma/network/peering.py deleted file mode 100644 index 15f598d9e036850d652b3ea03f01a81d1eb68d19..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/network/peering.py +++ /dev/null @@ -1,106 +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 ucoinpy.api.bma.network 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.""" - schema = { - "type": ["object"], - "properties": { - "depth": { - "type": "number" - }, - "nodesCount": { - "type": "number" - }, - "leavesCount": { - "type": "number" - }, - "root": { - "type": "string" - }, - "hash": { - "type": "string" - }, - "value": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "endpoints": { - "type": "array", - "items": { - "type": "string" - } - }, - "signature": { - "type": "string" - } - }, - "required": ["version", "currency", "pubkey", "endpoints", "signature"] - } - }, - "oneOf": [ - { - "required": ["depth", "nodesCount", "leavesCount", "root"] - }, - { - "required": ["hash", "value"] - } - ] - } - - async def __get__(self, session, **kwargs): - """creates a generator with one peering entry per iteration.""" - - r = await self.requests_get(session, '/peers', **kwargs) - return (await self.parse_response(r)) - - async def __post__(self, session, **kwargs): - assert 'entry' in kwargs - assert 'signature' in kwargs - - r = await self.requests_post(session, '/peers', **kwargs) - return r - - -class Status(Base): - """POST a network status document to this node in order notify of its status.""" - - async def __post__(self, session, **kwargs): - assert 'status' in kwargs - assert 'signature' in kwargs - - r = await self.requests_post(session, '/status', **kwargs) - return r diff --git a/ucoinpy/api/bma/node.py b/ucoinpy/api/bma/node.py deleted file mode 100644 index 30ff65b88ed8b72f27da78ed85a53d5f766277e1..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/node.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/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from ucoinpy.api.bma 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.""" - schema = { - "type": "object", - "properties": { - "ucoin": { - "type": "object", - "properties": { - "software": { - "type": "string" - }, - "version": { - "type": "string", - }, - "forkWindowSize": { - "type": "number" - } - }, - "required": ["software", "version"] - }, - }, - "required": ["ucoin"] - } - - def __init__(self, connection_handler, module='node'): - super(Summary, self).__init__(connection_handler, module) - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/summary', **kwargs) - return await self.parse_response(r) - diff --git a/ucoinpy/api/bma/tx/__init__.py b/ucoinpy/api/bma/tx/__init__.py deleted file mode 100644 index 85a3585aaddcf551a9560c8ec4f955266e170dc5..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/tx/__init__.py +++ /dev/null @@ -1,237 +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.""" - schema = { - "type": "object", - "properties": { - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "history": { - "type": "object", - "properties": { - "sent": { - "$ref": "#/definitions/transaction_data" - }, - "received": { - "$ref": "#/definitions/transaction_data" - }, - "sending": { - "$ref": "#/definitions/transactioning_data" - }, - "receiving": { - "$ref": "#/definitions/transactioning_data" - }, - }, - "required": ["sent", "received", "sending", "receiving"] - } - }, - "definitions": { - "transaction_data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "version": { - "type": "number" - }, - "issuers": { - "type": "array", - "items": { - "type": "string" - } - }, - "inputs": { - "type": "array", - "items": { - "type": "string" - } - }, - "outputs": { - "type": "array", - "items": { - "type": "string" - } - }, - "unlocks": { - "type": "array", - "items": { - "type": "string" - } - }, - "comment": { - "type": "string" - }, - "signatures": { - "type": "array", - "items": { - "type": "string" - } - }, - "hash": { - "type": "string" - }, - "block_number": { - "type": "number" - }, - "time": { - "type": "number" - } - }, - "required": ["version", "issuers", "inputs", "outputs", - "comment", "signatures", "hash", "block_number", "time"] - } - }, - "transactioning_data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "version": { - "type": "number" - }, - "issuers": { - "type": "array", - "items": { - "type": "string" - } - }, - "inputs": { - "type": "array", - "items": { - "type": "string" - } - }, - "outputs": { - "type": "array", - "items": { - "type": "string" - } - }, - "unlocks": { - "type": "array", - "items": { - "type": "string" - } - }, - "comment": { - "type": "string" - }, - "signatures": { - "type": "array", - "items": { - "type": "string" - } - }, - "hash": { - "type": "string" - }, - }, - "required": ["version", "issuers", "inputs", "outputs", - "comment", "signatures", "hash"] - } - } - }, - "required": ["currency", "pubkey", "history"] - } - - def __init__(self, conn_handler, pubkey, module='tx'): - super(Tx, self).__init__(conn_handler, module) - self.pubkey = pubkey - - async def __get__(self, session, **kwargs): - assert self.pubkey is not None - r = await self.requests_get(session, '/history/%s' % self.pubkey, **kwargs) - return await self.parse_response(r) - - -class Process(Tx): - """POST a transaction.""" - - async def __post__(self, session, **kwargs): - assert 'transaction' in kwargs - - r = await self.requests_post(session, '/process', **kwargs) - return r - - -class Sources(Tx): - """Get transaction sources.""" - schema = { - "type": "object", - "properties": { - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "sources": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "noffset": { - "type": "number" - }, - "identifier": { - "type": "string" - }, - "amount": { - "type": "number" - }, - "base": { - "type": "number" - } - }, - "required": ["type", "noffset", "identifier", "amount", "base"] - } - } - }, - "required": ["currency", "pubkey", "sources"] - } - - def __init__(self, connection_handler, pubkey, module='tx'): - super(Tx, self).__init__(connection_handler, module) - self.pubkey = pubkey - - async def __get__(self, session, **kwargs): - assert self.pubkey is not None - r = await self.requests_get(session, '/sources/%s' % self.pubkey, **kwargs) - return await self.parse_response(r) - - -from . import history diff --git a/ucoinpy/api/bma/tx/history.py b/ucoinpy/api/bma/tx/history.py deleted file mode 100644 index 1539afd73f711a57170e14229f35006cd20e91ec..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/tx/history.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Authors: -# Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from ucoinpy.api.bma.tx import History, logging - -logger = logging.getLogger("ucoin/tx") - - -class Blocks(History): - - schema = History.schema - - def __init__(self, conn_handler, pubkey, from_, to_, module='tx'): - super(Blocks, self).__init__(conn_handler, pubkey, module) - self.from_ = from_ - self.to_ = to_ - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/history/%s/blocks/%s/%s' % (self.pubkey, self.from_, self.to_), **kwargs) - return await self.parse_response(r) \ No newline at end of file diff --git a/ucoinpy/api/bma/ud.py b/ucoinpy/api/bma/ud.py deleted file mode 100644 index 1738f2e87233d8d1f38fea61a91f11518fca8d3d..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/ud.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 ucoinpy.api.bma 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 - - async def __get__(self, session, **kwargs): - assert self.pubkey is not None - r = await self.requests_get(session, '/history/%s' % self.pubkey, **kwargs) - return await r.json() diff --git a/ucoinpy/api/bma/wot.py b/ucoinpy/api/bma/wot.py deleted file mode 100644 index fa984b02e5940473343b5df2fde99aa786b0d8ba..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/wot.py +++ /dev/null @@ -1,307 +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 ucoinpy.api.bma 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 Identity data.""" - - async def __post__(self, session, **kwargs): - assert 'identity' in kwargs - - r = await self.requests_post(session, '/add', **kwargs) - return r - - -class Certify(WOT): - """POST Certification data.""" - - async def __post__(self, session, **kwargs): - assert 'cert' in kwargs - - r = await self.requests_post(session, '/certify', **kwargs) - return r - - -class Revoke(WOT): - """POST Public key data.""" - - async def __post__(self, session, **kwargs): - assert 'pubkey' in kwargs - assert 'self_' in kwargs - - r = await self.requests_post(session, '/revoke', **kwargs) - return r - - -class Lookup(WOT): - """GET Public key data.""" - schema = { - "type": "object", - "definitions": { - "meta_data": { - "type": "object", - "properties": { - "timestamp": { - "type": "string" - } - } - }, - }, - "properties": { - "partial": { - "type": "boolean" - }, - "results": { - "type": "array", - "items": { - "type": "object", - "properties": { - "pubkey": { - "type": "string" - } - }, - "uids": { - "type": "array", - "items": { - "type": "object", - "properties": { - "uid": { - "type": "string" - }, - "meta": { - "$ref": "#/definitions/meta_data" - }, - "self": { - "type": "string", - }, - "revokation_sig": { - "type": "string" - }, - "revoked": { - "type": "boolean" - }, - "others": { - "type": "array", - "items": { - "type": "object", - "properties": { - "pubkey": { - "type": "string", - }, - "meta": { - "$ref": "#/definitions/meta_data" - }, - "signature": { - "type": "string" - } - } - } - } - }, - "required": ["uid", "meta", "self", "revokation_sig", "revoked", "others"] - } - }, - "signed": { - "type": "array", - "items": { - "type": "object", - "properties": { - "uid": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "meta": { - "$ref": "#/definitions/meta_data" - }, - "signature": { - "type": "string" - }, - "revokation_sig": { - "type": "string" - }, - "revoked": { - "type": "boolean" - } - }, - "required": ["uid", "pubkey", "meta", "revokation_sig", "revoked", "signature"] - } - }, - "required": ["uids", "signed"] - } - } - }, - "required": ["partial", "results"] - } - - def __init__(self, connection_handler, search, module='wot'): - super(WOT, self).__init__(connection_handler, module) - - self.search = search - - async def __get__(self, session, **kwargs): - assert self.search is not None - - r = await self.requests_get(session, '/lookup/%s' % self.search, **kwargs) - return await self.parse_response(r) - - -class CertifiersOf(WOT): - """GET Certification data over a member.""" - - schema = { - "type": "object", - "properties": { - "pubkey": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "isMember": { - "type": "boolean" - }, - "certifications": { - "type": "array", - "items": { - "type": "object", - "properties": { - "pubkey": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "cert_time": { - "type": "object", - "properties": { - "block": { - "type": "number" - }, - "medianTime": { - "type": "number" - } - }, - "required": ["block", "medianTime"] - }, - "sigDate": { - "type": "string" - }, - "written": { - "oneOf": [ - { - "type": "object", - "properties": { - "number": { - "type": "number", - }, - "hash": { - "type": "string" - } - }, - "required": ["number", "hash"] - }, - { - "type": "null" - } - ] - }, - "isMember": { - "type": "boolean" - }, - "wasMember": { - "type": "boolean" - }, - "signature": { - "type": "string" - } - }, - "required": ["pubkey", "uid", "cert_time", "sigDate", - "written", "wasMember", "isMember", "signature"] - } - } - }, - "required": ["pubkey", "uid", "isMember", "certifications"] - } - - def __init__(self, connection_handler, search, module='wot'): - super(WOT, self).__init__(connection_handler, module) - - self.search = search - - async def __get__(self, session, **kwargs): - assert self.search is not None - - r = await self.requests_get(session, '/certifiers-of/%s' % self.search, **kwargs) - return await self.parse_response(r) - - -class CertifiedBy(WOT): - """GET Certification data from a member.""" - - schema = CertifiersOf.schema - - def __init__(self, connection_handler, search, module='wot'): - super(WOT, self).__init__(connection_handler, module) - - self.search = search - - async def __get__(self, session, **kwargs): - assert self.search is not None - - r = await self.requests_get(session, '/certified-by/%s' % self.search, **kwargs) - return await self.parse_response(r) - - -class Members(WOT): - """GET List all current members of the Web of Trust.""" - schema = { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "type": "object", - "properties": { - "pubkey": { - "type": "string" - } - }, - "required": ["pubkey"] - } - } - }, - "required": ["results"] - } - - def __init__(self, connection_handler, module='wot'): - super(WOT, self).__init__(connection_handler, module) - - async def __get__(self, session, **kwargs): - r = await self.requests_get(session, '/members', **kwargs) - return (await self.parse_response(r)) diff --git a/ucoinpy/api/bma/ws.py b/ucoinpy/api/bma/ws.py deleted file mode 100644 index 8276796d33224e65aede658c75d479003cdc9453..0000000000000000000000000000000000000000 --- a/ucoinpy/api/bma/ws.py +++ /dev/null @@ -1,69 +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 ucoinpy.api.bma import API, logging -from ucoinpy.api.bma.blockchain import Block as _Block -from ucoinpy.api.bma.network.peering import Peers as _Peers - -logger = logging.getLogger("ucoin/ws") - - -class Websocket(API): - def __init__(self, connection_handler, module='ws'): - super(Websocket, self).__init__(connection_handler, module) - - -class Block(Websocket): - """Connect to block websocket.""" - schema = _Block.schema - - def connect(self, session): - r = self.connect_ws(session, '/block') - return r - - -class Peer(Websocket): - """Connect to block websocket.""" - schema = { - "type": "object", - "properties": { - "version": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "endpoints": { - "type": "array", - "items": { - "type": "string" - } - }, - "signature": { - "type": "string" - } - }, - "required": ["version", "currency", "pubkey", "endpoints", "signature"] - } - - def connect(self, session): - r = self.connect_ws(session, '/peer') - return r diff --git a/ucoinpy/api/errors.py b/ucoinpy/api/errors.py deleted file mode 100644 index a0ed22d001303cd9bea0ab9384d836fbdfb8dfd5..0000000000000000000000000000000000000000 --- a/ucoinpy/api/errors.py +++ /dev/null @@ -1,45 +0,0 @@ - -class UcoinError(Exception): - """ - UCoin error - """ - def __init__(self, data): - super().__init__("Error code {0} - {1}".format(data["ucode"], data["message"])) - self.ucode = data["ucode"] - self.message = data["message"] - -UNKNOWN = 1001 -UNHANDLED = 1002 -SIGNATURE_DOES_NOT_MATCH = 1003 -ALREADY_UP_TO_DATE = 1004 -WRONG_DOCUMENT = 1005 - -HTTP_PARAM_PUBKEY_REQUIRED = 1101 -HTTP_PARAM_IDENTITY_REQUIRED = 1102 -HTTP_PARAM_PEER_REQUIRED = 1103 -HTTP_PARAM_BLOCK_REQUIRED = 1104 -HTTP_PARAM_MEMBERSHIP_REQUIRED = 1105 -HTTP_PARAM_TX_REQUIRED = 1106 -HTTP_PARAM_SIG_REQUIRED = 1107 -HTTP_PARAM_CERT_REQUIRED = 1108 -HTTP_PARAM_REVOCATION_REQUIRED = 1109 -HTTP_PARAM_CONF_REQUIRED = 1110 - -NO_MATCHING_IDENTITY = 2001 -UID_ALREADY_USED = 2002 -PUBKEY_ALREADY_USED = 2003 -NO_MEMBER_MATCHING_PUB_OR_UID = 2004 -SELF_PEER_NOT_FOUND = 2005 -WRONG_SIGNATURE_MEMBERSHIP = 2006 -ALREADY_RECEIVED_MEMBERSHIP = 2007 -MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE = 2008 -NOT_A_MEMBER = 2009 -NO_CURRENT_BLOCK = 2010 -BLOCK_NOT_FOUND = 2011 -PEER_NOT_FOUND = 2012 -WRONG_UNLOCKER = 2013 -LOCKTIME_PREVENT = 2014 -SOURCE_ALREADY_CONSUMED = 2015 -WRONG_AMOUNTS = 2016 -WRONG_OUTPUT_BASE = 2017 -CANNOT_ROOT_BLOCK_NO_MEMBERS = 2018 \ No newline at end of file diff --git a/ucoinpy/documents/__init__.py b/ucoinpy/documents/__init__.py deleted file mode 100644 index dec8379a1dfb057b1175447d0a193bcac626ab08..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .block import Block, BlockUID -from .certification import SelfCertification, Certification, Revokation -from .membership import Membership -from .peer import Endpoint, BMAEndpoint, UnknownEndpoint, Peer -from .transaction import SimpleTransaction, Transaction -from .document import Document, MalformedDocumentError - -from . import constants \ No newline at end of file diff --git a/ucoinpy/documents/block.py b/ucoinpy/documents/block.py deleted file mode 100644 index 2eed65a52a64fa0e72f2481d94ce033be95b60d3..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/block.py +++ /dev/null @@ -1,439 +0,0 @@ -from .document import Document, MalformedDocumentError -from .certification import SelfCertification, Certification, Revokation -from .membership import Membership -from .transaction import Transaction -from .constants import pubkey_regex, block_id_regex, block_hash_regex - -import re - - -class BlockUID: - """ - A simple block id - """ - re_block_uid = re.compile("({block_id_regex})-({block_hash_regex})".format(block_id_regex=block_id_regex, - block_hash_regex=block_hash_regex)) - re_hash = re.compile("({block_hash_regex})".format(block_hash_regex=block_hash_regex)) - - @classmethod - def empty(cls): - return cls(0, Block.Empty_Hash) - - def __init__(self, number, sha_hash): - assert(type(number) is int) - assert(BlockUID.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 = BlockUID.re_block_uid.match(blockid) - try: - number = int(data.group(1)) - except AttributeError: - raise MalformedDocumentError("BlockUID") - - try: - sha_hash = data.group(2) - except AttributeError: - raise MalformedDocumentError("BlockHash") - - return cls(number, sha_hash) - - def __str__(self): - return "{0}-{1}".format(self.number, self.sha_hash) - - def __eq__(self, other): - return self.number == other.number and self.sha_hash == other.sha_hash - - def __lt__(self, other): - return self.number < other.number - - def __gt__(self, other): - return self.number > other.number - - def __le__(self, other): - return self.number <= other.number - - def __ge__(self, other): - return self.number >= other.number - - -class Block(Document): - """ -The class Block handles Block documents. - -.. note:: A block document is specified by the following format : - - | 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_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_unitbase = re.compile("UnitBase: ([0-6])\n") - re_issuer = re.compile("Issuer: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - re_previoushash = re.compile("PreviousHash: ({block_hash_regex})\n".format(block_hash_regex=block_hash_regex)) - re_previousissuer = re.compile("PreviousIssuer: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - 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]+):([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_revoked = re.compile("Revoked:\n") - re_excluded = re.compile("Excluded:\n") - re_exclusion = re.compile("({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - re_certifications = re.compile("Certifications:\n") - re_transactions = re.compile("Transactions:\n") - re_hash = re.compile("InnerHash: ({block_hash_regex})\n".format(block_hash_regex=block_hash_regex)) - re_noonce = re.compile("Nonce: ([0-9]+)\n") - - fields_parsers = {**Document.fields_parsers, **{ - 'Type': re_type, - 'Number': re_number, - 'PoWMin': re_powmin, - 'Time': re_time, - 'MedianTime': re_mediantime, - 'UD': re_universaldividend, - 'UnitBase': re_unitbase, - 'Issuer': re_issuer, - 'PreviousIssuer': re_previousissuer, - 'PreviousHash': re_previoushash, - 'Parameters': re_parameters, - 'MembersCount': re_memberscount, - 'Identities': re_identities, - 'Joiners': re_joiners, - 'Actives': re_actives, - 'Leavers': re_leavers, - 'Revoked': re_revoked, - 'Excluded': re_excluded, - 'Certifications': re_certifications, - 'Transactions': re_transactions, - 'InnerHash': re_hash, - 'Noonce': re_noonce, - } - } - - Empty_Hash = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" - - def __init__(self, version, currency, number, powmin, time, - mediantime, ud, unit_base, issuer, prev_hash, prev_issuer, - parameters, members_count, identities, joiners, - actives, leavers, revokations, excluded, certifications, - transactions, inner_hash, noonce, signature): - """ - Constructor - - :param int version: ucoin protocol version - :param str currency: the block currency - :param int number: the number of the block - :param int powmin: the powmin value of this block - :param int time: the timestamp of this block - :param int ud: the dividend amount, or None if no dividend present in this block - :param int unit_base: the unit_base of the dividend, or None if no dividend present in this block - :param str issuer: the pubkey of the issuer of the block - :param str prev_hash: the previous block hash - :param str prev_issuer: the previous block issuer - :param tuple parameters: the parameters of the currency. Should only be present in block 0. - :param int members_count: the number of members found in this block - :param list[ucoinpy.documents.SelfCertification] identities: the self certifications declared in this block - :param list[ucoinpy.documents.Membership] joiners: the joiners memberships via "IN" documents - :param list[ucoinpy.documents.Membership] actives: renewed memberships via "IN" documents - :param list[ucoinpy.documents.Membership] leavers: the leavers memberships via "OUT" documents - :param list[ucoinpy.documents.Revokation] revokations: revokations - :param list[ucoinpy.documents.Membership] excluded: members excluded because of missing certifications - :param list[ucoinpy.documents.Membership] actives: renewed memberships via "IN" documents - :param list[ucoinpy.documents.Certification] certifications: certifications documents - :param list[ucoinpy.documents.Transaction] transactions: transactions documents - :param str inner_hash: the block hah - :param int noonce: the noonce value of the block - :param list[str] signatures: the block signaturezs - """ - super().__init__(version, currency, [signature]) - self.number = number - self.powmin = powmin - self.time = time - self.mediantime = mediantime - self.ud = ud - self.unit_base = unit_base - 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.revoked = revokations - self.excluded = excluded - self.certifications = certifications - self.transactions = transactions - self.inner_hash = inner_hash - self.noonce = noonce - - @property - def blockUID(self): - return BlockUID(self.number, self.sha_hash) - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Block.parse_field("Version", lines[n])) - n += 1 - - Block.parse_field("Type", lines[n]) - n += 1 - - currency = Block.parse_field("Currency", lines[n]) - n += 1 - - number = int(Block.parse_field("Number", lines[n])) - n += 1 - - powmin = int(Block.parse_field("PoWMin", lines[n])) - n += 1 - - time = int(Block.parse_field("Time", lines[n])) - n += 1 - - mediantime = int(Block.parse_field("MedianTime", lines[n])) - n += 1 - - ud = Block.re_universaldividend.match(lines[n]) - unit_base = None - if ud is not None: - ud = int(Block.parse_field("UD", lines[n])) - n += 1 - - unit_base = int(Block.parse_field("UnitBase", lines[n])) - n += 1 - - issuer = Block.parse_field("Issuer", lines[n]) - n += 1 - - prev_hash = None - prev_issuer = None - if number > 0: - prev_hash = Block.parse_field("PreviousHash", lines[n]) - n += 1 - - prev_issuer = Block.parse_field("PreviousIssuer", lines[n]) - n += 1 - - parameters = None - if number == 0: - try: - parameters = Block.re_parameters.match(lines[n]).groups() - n += 1 - except AttributeError: - raise MalformedDocumentError("Parameters") - - members_count = int(Block.parse_field("MembersCount", lines[n])) - n += 1 - - identities = [] - joiners = [] - actives = [] - leavers = [] - revoked = [] - excluded = [] - certifications = [] - transactions = [] - - if Block.re_identities.match(lines[n]) is not None: - n += 1 - while Block.re_joiners.match(lines[n]) is None: - selfcert = SelfCertification.from_inline(version, currency, lines[n]) - identities.append(selfcert) - n += 1 - - if Block.re_joiners.match(lines[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 += 1 - - if Block.re_actives.match(lines[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 += 1 - - if Block.re_leavers.match(lines[n]): - n += 1 - while Block.re_revoked.match(lines[n]) is None: - membership = Membership.from_inline(version, currency, "OUT", lines[n]) - leavers.append(membership) - n += 1 - - if Block.re_revoked.match(lines[n]): - n += 1 - while Block.re_excluded.match(lines[n]) is None: - revokation = Revokation.from_inline(version, currency, lines[n]) - revoked.append(revokation) - n += 1 - - if Block.re_excluded.match(lines[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 += 1 - - if Block.re_certifications.match(lines[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 += 1 - - if Block.re_transactions.match(lines[n]): - n += 1 - while not Block.re_hash.match(lines[n]): - tx_lines = "" - header_data = Transaction.re_header.match(lines[n]) - if header_data is None: - raise MalformedDocumentError("Compact transaction ({0})".format(lines[n])) - version = int(header_data.group(1)) - issuers_num = int(header_data.group(2)) - inputs_num = int(header_data.group(3)) - unlocks_num = int(header_data.group(4)) - outputs_num = int(header_data.group(5)) - has_comment = int(header_data.group(6)) - tx_max = n + 1 + issuers_num * 2 + inputs_num + unlocks_num + outputs_num + has_comment - for i in range(n, tx_max): - tx_lines += lines[n] - n += 1 - transaction = Transaction.from_compact(currency, tx_lines) - transactions.append(transaction) - - inner_hash = Block.parse_field("InnerHash", lines[n]) - n += 1 - - noonce = int(Block.parse_field("Noonce", lines[n])) - n += 1 - - signature = Block.parse_field("Signature", lines[n]) - - return cls(version, currency, number, powmin, time, - mediantime, ud, unit_base, issuer, prev_hash, prev_issuer, - parameters, members_count, identities, joiners, - actives, leavers, revoked, excluded, certifications, - transactions, inner_hash, noonce, signature) - - def raw(self): - doc = """Version: {version} -Type: Block -Currency: {currency} -Number: {number} -PoWMin: {powmin} -Time: {time} -MedianTime: {mediantime} -""".format(version=self.version, - currency=self.currency, - number=self.number, - powmin=self.powmin, - time=self.time, - mediantime=self.mediantime) - if self.ud: - doc += "UniversalDividend: {0}\n".format(self.ud) - doc += "UnitBase: {0}\n".format(self.unit_base) - - 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 += "Revoked:\n" - for revokation in self.revoked: - doc += "{0}\n".format(revokation) - - 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}".format(transaction.compact()) - - doc += "InnerHash: {0}\n".format(self.inner_hash) - - doc += "Nonce: {0}\n".format(self.noonce) - - return doc \ No newline at end of file diff --git a/ucoinpy/documents/certification.py b/ucoinpy/documents/certification.py deleted file mode 100644 index bc21a693e21ee5d681d13763e41ca344fffe88fe..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/certification.py +++ /dev/null @@ -1,234 +0,0 @@ -import re -import base64 -import logging - -from .document import Document, MalformedDocumentError -from .constants import pubkey_regex, signature_regex, block_id_regex, block_uid_regex - - -class SelfCertification(Document): - """ - A document discribing a self certification. - """ - - re_inline = re.compile("({pubkey_regex}):({signature_regex}):({block_uid_regex}):([^\n]+)\n" - .format(pubkey_regex=pubkey_regex, - signature_regex=signature_regex, - block_uid_regex=block_uid_regex)) - re_uid = re.compile("UID:([^\n]+)\n") - re_timestamp = re.compile("META:TS:({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) - - def __init__(self, version, currency, pubkey, uid, ts, 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): - from .block import BlockUID - - selfcert_data = SelfCertification.re_inline.match(inline) - if selfcert_data is None: - raise MalformedDocumentError("Inline self certification") - pubkey = selfcert_data.group(1) - signature = selfcert_data.group(2) - ts = BlockUID.from_str(selfcert_data.group(3)) - uid = selfcert_data.group(4) - - return cls(version, currency, pubkey, uid, ts, signature) - - def raw(self): - return """Version: {version} -Type: Identity -Currency: {currency} -Issuer: {pubkey} -UniqueID: {uid} -Timestamp: {timestamp} -""".format(version=self.version, - currency=self.currency, - pubkey=self.pubkey, - uid=self.uid, - timestamp=self.timestamp) - - def inline(self): - return "{pubkey}:{signature}:{timestamp}:{uid}".format( - pubkey=self.pubkey, - signature=self.signatures[0], - timestamp=self.timestamp, - uid=self.uid) - - -class Certification(Document): - """ - A document describing a certification. - """ - - re_inline = re.compile("({certifier_regex}):({certified_regex}):({block_id_regex}):({signature_regex})\n".format( - certifier_regex=pubkey_regex, - certified_regex=pubkey_regex, - block_id_regex=block_id_regex, - signature_regex=signature_regex - )) - re_timestamp = re.compile("META:TS:({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) - - def __init__(self, version, currency, pubkey_from, pubkey_to, - timestamp, signature): - """ - Constructor - - :param str version: the UCP version - :param str currency: the currency of the blockchain - :param str pubkey_from: - :param str pubkey_to: - :param BlockUID timestamp: the blockuid - :param str signature: the signature of the document - """ - super().__init__(version, currency, [signature]) - self.pubkey_from = pubkey_from - self.pubkey_to = pubkey_to - self.timestamp = timestamp - - @classmethod - def from_inline(cls, version, currency, blockhash, inline): - """ - From inline version in block - :param version: - :param currency: - :param blockhash: - :param inline: - :return: - """ - from .block import Block, BlockUID - cert_data = Certification.re_inline.match(inline) - if cert_data is None: - raise MalformedDocumentError("Certification ({0})".format(inline)) - pubkey_from = cert_data.group(1) - pubkey_to = cert_data.group(2) - blockid = int(cert_data.group(3)) - if blockid == 0: - timestamp = BlockUID.empty() - else: - timestamp = BlockUID(blockid, blockhash) - - signature = cert_data.group(4) - return cls(version, currency, pubkey_from, pubkey_to, timestamp, signature) - - def raw(self, selfcert): - """ - - :param SelfCertification selfcert: - :return: - """ - return """Version: {version} -Type: Certification -Currency: {currency} -Issuer: {issuer} -IdtyIssuer: {certified_pubkey} -IdtyUniqueID: {certified_uid} -IdtyTimestamp: {certified_ts} -IdtySignature: {certified_signature} -CertTimestamp: {timestamp} -""".format(version=self.version, - currency=self.currency, - issuer=self.pubkey_from, - certified_pubkey=selfcert.pubkey, - certified_uid=selfcert.uid, - certified_ts=selfcert.timestamp, - certified_signature=selfcert.signatures[0], - timestamp=self.timestamp) - - 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.timestamp.number, self.signatures[0]) - - -class Revokation(Document): - """ - A document describing a self-revocation. - """ - re_inline = re.compile("({pubkey_regex}):({signature_regex})\n".format( - pubkey_regex=pubkey_regex, - signature_regex=signature_regex - )) - - def __init__(self, version, currency, pubkey, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - self.pubkey = pubkey - - @classmethod - def from_inline(cls, version, currency, inline): - """ - From inline version in block - :param int version: - :param str currency: - :param str pubkey: - :param str signature: - :return: - """ - cert_data = Revokation.re_inline.match(inline) - if cert_data is None: - raise MalformedDocumentError("Revokation") - pubkey = cert_data.group(1) - signature = cert_data.group(2) - return cls(version, currency, pubkey, signature) - - - def raw(self, selfcert): - """ - - :param SelfCertification selfcert: - :return: - """ - return """Version: {version} -Type: Revocation -Currency: {currency} -Issuer: {pubkey} -IdtyUniqueID: {uid} -IdtyTimestamp: {timestamp} -IdtySignature: {signature} -""".format(version=self.version, - currency=self.currency, - pubkey=selfcert.pubkey, - uid=selfcert.uid, - timestamp=selfcert.timestamp, - signature=selfcert.signatures[0]) - - 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")) - - def signed_raw(self, selfcert): - raw = self.raw(selfcert) - signed = "\n".join(self.signatures) - signed_raw = raw + signed + "\n" - return signed_raw diff --git a/ucoinpy/documents/constants.py b/ucoinpy/documents/constants.py deleted file mode 100644 index 282558e30853d4eb472d26dc6407685c6e813e1f..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/constants.py +++ /dev/null @@ -1,8 +0,0 @@ - -pubkey_regex = "(?![OIl])[1-9A-Za-z]{42,45}" -signature_regex = "[A-Za-z0-9+/]+(?:=|==)?" -block_hash_regex = "[0-9a-fA-F]{5,64}" -transaction_hash_regex = "[0-9a-fA-F]{5,64}" -block_id_regex = "[0-9]+" -block_uid_regex = "{block_id_regex}-{block_hash_regex}".format(block_id_regex=block_id_regex, - block_hash_regex=block_hash_regex) \ No newline at end of file diff --git a/ucoinpy/documents/document.py b/ucoinpy/documents/document.py deleted file mode 100644 index 514c107abf5bba9147188f79011564968186fe0e..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/document.py +++ /dev/null @@ -1,74 +0,0 @@ -import base64 -import re -import logging -import hashlib -from .constants import signature_regex - - -class MalformedDocumentError(Exception): - """ - Malformed document exception - """ - def __init__(self, field_name): - super().__init__("Could not parse field {0}".format(field_name)) - - -class Document: - re_version = re.compile("Version: ([0-9]+)\n") - re_currency = re.compile("Currency: ([^\n]+)\n") - re_signature = re.compile("({signature_regex})\n".format(signature_regex=signature_regex)) - - fields_parsers = { - "Version": re_version, - "Currency": re_currency, - "Signature": re_signature - } - - @classmethod - def parse_field(cls, field_name, line): - """ - - :param field_name: - :param line: - :return: - """ - try: - value = cls.fields_parsers[field_name].match(line).group(1) - except AttributeError: - raise MalformedDocumentError(field_name) - return value - - def __init__(self, version, currency, signatures): - if version < 2: - raise MalformedDocumentError("Version 1 documents are not handled by ucoinpy>0.2") - 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.sha256(self.signed_raw().encode("ascii")).hexdigest().upper() diff --git a/ucoinpy/documents/membership.py b/ucoinpy/documents/membership.py deleted file mode 100644 index 068b0dafca56441f3c630129f4c80a0939a991d2..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/membership.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Created on 2 déc. 2014 - -@author: inso -""" -from .document import Document, MalformedDocumentError -from .constants import block_uid_regex, signature_regex, pubkey_regex - -import re - - -class Membership(Document): - """ -.. note:: A membership document is specified by the following format : - - | 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("({pubkey_regex}):({signature_regex}):({ms_block_uid_regex}):({identity_block_uid_regex}):([^\n]+)\n" - .format(pubkey_regex=pubkey_regex, signature_regex=signature_regex, - ms_block_uid_regex=block_uid_regex, - identity_block_uid_regex=block_uid_regex)) - re_type = re.compile("Type: (Membership)") - re_issuer = re.compile("Issuer: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - re_block = re.compile("Block: ({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) - re_membership_type = re.compile("Membership: (IN|OUT)") - re_userid = re.compile("UserID: ([^\n]+)\n") - re_certts = re.compile("CertTS: ({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) - - fields_parsers = {**Document.fields_parsers, **{ - "Type": re_type, - "Issuer": re_issuer, - "Block": re_block, - "Membership": re_membership_type, - "UserID": re_userid, - "CertTS": re_certts - }} - - def __init__(self, version, currency, issuer, membership_ts, - membership_type, uid, identity_ts, signature): - """ - Constructor - """ - super().__init__(version, currency, [signature]) - self.issuer = issuer - self.membership_ts = membership_ts - self.membership_type = membership_type - self.uid = uid - self.identity_ts = identity_ts - - @classmethod - def from_inline(cls, version, currency, membership_type, inline): - from .block import BlockUID - data = Membership.re_inline.match(inline) - if data is None: - raise MalformedDocumentError("Inline membership ({0})".format(inline)) - issuer = data.group(1) - signature = data.group(2) - membership_ts = BlockUID.from_str(data.group(3)) - identity_ts = BlockUID.from_str(data.group(4)) - uid = data.group(5) - return cls(version, currency, issuer, membership_ts, membership_type, uid, identity_ts, signature) - - @classmethod - def from_signed_raw(cls, raw, signature=None): - from .block import BlockUID - lines = raw.splitlines(True) - n = 0 - - version = int(Membership.parse_field("Version", lines[n])) - n += 1 - - Membership.parse_field("Type", lines[n]) - n += 1 - - currency = Membership.parse_field("Currency", lines[n]) - n += 1 - - issuer = Membership.parse_field("Issuer", lines[n]) - n += 1 - - membership_ts = BlockUID.from_str(Membership.parse_field("Block", lines[n])) - n += 1 - - membership_type = Membership.parse_field("Membership", lines[n]) - n += 1 - - uid = Membership.parse_field("UserID", lines[n]) - n += 1 - - identity_ts = BlockUID.from_str(Membership.parse_field("CertTS", lines[n])) - n += 1 - - signature = Membership.parse_field("Signature", lines[n]) - n += 1 - - return cls(version, currency, issuer, membership_ts, - membership_type, uid, identity_ts, signature) - - def raw(self): - return """Version: {0} -Type: Membership -Currency: {1} -Issuer: {2} -Block: {3} -Membership: {4} -UserID: {5} -CertTS: {6} -""".format(self.version, - self.currency, - self.issuer, - self.membership_ts, - self.membership_type, - self.uid, - self.identity_ts) - - def inline(self): - return "{0}:{1}:{2}:{3}:{4}".format(self.issuer, - self.signatures[0], - self.membership_ts, - self.identity_ts, - self.uid) diff --git a/ucoinpy/documents/peer.py b/ucoinpy/documents/peer.py deleted file mode 100644 index d37b33bad9fe26e1c4de225f212bd0eeb810eb16..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/peer.py +++ /dev/null @@ -1,160 +0,0 @@ -import re - -from ..api.bma import ConnectionHandler -from .document import Document, MalformedDocumentError -from . import BlockUID -from .. import PROTOCOL_VERSION, MANAGED_API -from .constants import block_hash_regex, pubkey_regex - -class Peer(Document): - """ -.. note:: A peer document is specified by the following format : - - | 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: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - re_block = re.compile("Block: ([0-9]+-{block_hash_regex})\n".format(block_hash_regex=block_hash_regex)) - re_endpoints = re.compile("(Endpoints:)\n") - - fields_parsers = {**Document.fields_parsers, **{ - "Type": re_type, - "Pubkey": re_pubkey, - "Block": re_block, - "Endpoints": re_endpoints - }} - - def __init__(self, version, currency, pubkey, blockUID, - endpoints, signature): - super().__init__(version, currency, [signature]) - - self.pubkey = pubkey - self.blockUID = blockUID - self.endpoints = endpoints - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Peer.parse_field("Version", lines[n])) - n += 1 - - Peer.parse_field("Type", lines[n]) - n += 1 - - currency = Peer.parse_field("Currency", lines[n]) - n += 1 - - pubkey = Peer.parse_field("Pubkey", lines[n]) - n += 1 - - blockUID = BlockUID.from_str(Peer.parse_field("Block", lines[n])) - n += 1 - - Peer.parse_field("Endpoints", lines[n]) - n += 1 - - endpoints = [] - while not Peer.re_signature.match(lines[n]): - endpoint = Endpoint.from_inline(lines[n]) - endpoints.append(endpoint) - n += 1 - - signature = Peer.re_signature.match(lines[n]).group(1) - - return cls(version, currency, pubkey, blockUID, 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.blockUID) - - for endpoint in self.endpoints: - doc += "{0}\n".format(endpoint.inline()) - - 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) - if m is None: - raise MalformedDocumentError("BMAEndpoint") - 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/ucoinpy/documents/transaction.py b/ucoinpy/documents/transaction.py deleted file mode 100644 index 028ff116a2be3682d257f2d305711fc657585f74..0000000000000000000000000000000000000000 --- a/ucoinpy/documents/transaction.py +++ /dev/null @@ -1,494 +0,0 @@ -from .document import Document, MalformedDocumentError -from .constants import pubkey_regex, transaction_hash_regex, block_id_regex -from ..grammars import output -import pypeg2 -import re - - -def reduce_base(amount, base): - """ - Compute the reduced base of the given parameters - :param int amount: the amount value - :param int base: current base value - :return: tuple containing computed (amount, base) - :rtype: tuple - """ - if amount == 0: - return 0, 0 - - next_amount = amount - next_base = base - while int(next_amount) == next_amount: - amount = next_amount - base = next_base - next_amount /= 10 - next_base += 1 - return int(amount), int(base) - - -class Transaction(Document): - """ -.. note:: A transaction document is specified by the following format : - - | 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-9]+):(0|1):([0-9]+)\n") - re_locktime = re.compile("Locktime: ([0-9]+)\n") - re_issuers = re.compile("Issuers:\n") - re_inputs = re.compile("Inputs:\n") - re_unlocks = re.compile("Unlocks:\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("({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) - - fields_parsers = {**Document.fields_parsers, **{ - "Type": re_type, - "Locktime": re_locktime, - "TX": re_header, - "Issuers": re_issuers, - "Inputs": re_inputs, - "Unlocks": re_unlocks, - "Outputs": re_outputs, - "Comment": re_comment, - "Compact comment": re_compact_comment, - "Pubkey": re_pubkey - } - } - - def __init__(self, version, currency, locktime, issuers, inputs, unlocks, outputs, - comment, signatures): - """ - Constructor - """ - super().__init__(version, currency, signatures) - - self.locktime = locktime - self.issuers = issuers - self.inputs = inputs - self.unlocks = unlocks - 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]) - if header_data is None: - raise MalformedDocumentError("Compact TX header") - version = int(header_data.group(1)) - issuers_num = int(header_data.group(2)) - inputs_num = int(header_data.group(3)) - unlocks_num = int(header_data.group(4)) - outputs_num = int(header_data.group(5)) - has_comment = int(header_data.group(6)) - locktime = int(header_data.group(7)) - n += 1 - - issuers = [] - inputs = [] - unlocks = [] - outputs = [] - signatures = [] - for i in range(0, issuers_num): - issuer = Transaction.parse_field("Pubkey", lines[n]) - issuers.append(issuer) - n += 1 - - for i in range(0, inputs_num): - input_source = InputSource.from_inline(lines[n]) - inputs.append(input_source) - n += 1 - - for i in range(0, unlocks_num): - unlock = Unlock.from_inline(lines[n]) - unlocks.append(unlock) - n += 1 - - for i in range(0, outputs_num): - output_source = OutputSource.from_inline(lines[n]) - outputs.append(output_source) - n += 1 - - comment = "" - if has_comment == 1: - if Transaction.re_compact_comment.match(lines[n]): - comment = Transaction.re_compact_comment.match(lines[n]).group(1) - n += 1 - else: - raise MalformedDocumentError("Compact TX Comment") - - while n < len(lines): - if Transaction.re_signature.match(lines[n]): - signatures.append(Transaction.re_signature.match(lines[n]).group(1)) - n += 1 - else: - raise MalformedDocumentError("Compact TX Signatures") - - return cls(version, currency, locktime, issuers, inputs, unlocks, outputs, comment, signatures) - - @classmethod - def from_signed_raw(cls, raw): - lines = raw.splitlines(True) - n = 0 - - version = int(Transaction.parse_field("Version", lines[n])) - n += 1 - - Transaction.parse_field("Type", lines[n]) - n += 1 - - currency = Transaction.parse_field("Currency", lines[n]) - n += 1 - - locktime = Transaction.parse_field("Locktime", lines[n]) - n += 1 - - issuers = [] - inputs = [] - unlocks = [] - outputs = [] - signatures = [] - - if Transaction.re_issuers.match(lines[n]): - n += 1 - while Transaction.re_inputs.match(lines[n]) is None: - issuer = Transaction.parse_field("Pubkey", lines[n]) - issuers.append(issuer) - n += 1 - - if Transaction.re_inputs.match(lines[n]): - n += 1 - while Transaction.re_unlocks.match(lines[n]) is None: - input_source = InputSource.from_inline(lines[n]) - inputs.append(input_source) - n += 1 - - if Transaction.re_unlocks.match(lines[n]): - n += 1 - while Transaction.re_outputs.match(lines[n]) is None: - unlock = Unlock.from_inline(lines[n]) - unlocks.append(unlock) - n += 1 - - if Transaction.re_outputs.match(lines[n]) is not None: - n += 1 - while not Transaction.re_comment.match(lines[n]): - output = OutputSource.from_inline(lines[n]) - outputs.append(output) - n += 1 - - comment = Transaction.parse_field("Comment", lines[n]) - n += 1 - - if Transaction.re_signature.match(lines[n]) is not None: - while n < len(lines): - sign = Transaction.parse_field("Signature", lines[n]) - signatures.append(sign) - n += 1 - - return cls(version, currency, locktime, issuers, inputs, unlocks, outputs, - comment, signatures) - - def raw(self): - doc = """Version: {0} -Type: Transaction -Currency: {1} -Locktime: {2} -Issuers: -""".format(self.version, - self.currency, - self.locktime) - - 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 += "Unlocks:\n" - for u in self.unlocks: - doc += "{0}\n".format(u.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_UNLOCKS:NB_OUTPUTS:HAS_COMMENT:LOCKTIME -PUBLIC_KEY:INDEX -... -INDEX:SOURCE:FINGERPRINT:AMOUNT -... -PUBLIC_KEY:AMOUNT -... -COMMENT -""" - doc = "TX:{0}:{1}:{2}:{3}:{4}:{5}:{6}\n".format(self.version, - len(self.issuers), - len(self.inputs), - len(self.unlocks), - len(self.outputs), - '1' if self.comment != "" else '0', - self.locktime) - for pubkey in self.issuers: - doc += "{0}\n".format(pubkey) - for i in self.inputs: - doc += "{0}\n".format(i.inline()) - for u in self.unlocks: - doc += "{0}\n".format(u.inline()) - 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]) - - @staticmethod - def is_simple(tx): - """ - Filter a transaction and checks if it is a basic one - A simple transaction is a tx which has only one issuer - and two outputs maximum. The unlocks must be done with - simple "SIG" functions, and the outputs must be simple - SIG conditions. - :param ucoinpy.documents.Transaction tx: the transaction to check - :return: True if a simple transaction - """ - simple = True - if len(tx.issuers) != 1: - simple = False - for unlock in tx.unlocks: - if len(unlock.parameters) != 1: - simple = False - elif type(unlock.parameters[0]) is not SIGParameter: - simple = False - for o in tx.outputs: - if getattr('right', o.conditions, None): - simple = False - elif type(o.conditions.left) is not output.SIG: - simple = False - return simple - - -class InputSource: - """ - A Transaction INPUT - -.. note:: Compact : - INDEX:SOURCE:FINGERPRINT:AMOUNT - - """ - re_inline = re.compile("(?:(?:(D):({pubkey_regex}):({block_id_regex}))|(?:(T):({transaction_hash_regex}):([0-9]+)))\n" - .format(pubkey_regex=pubkey_regex, - block_id_regex=block_id_regex, - transaction_hash_regex=transaction_hash_regex)) - re_compact = re.compile("([0-9]+):(D|T):([0-9a-fA-F]{5,40}):([0-9]+)\n") - - def __init__(self, source, origin_id, index): - """ - An input source can come from a dividend or a transaction. - - :param str source: D if dividend, T if transaction - :param str origin_id: a Public key if a dividend, a tx hash if a transaction - :param int index: a block id if a dividend, an tx index if a transaction - :return: - """ - self.source = source - self.origin_id = origin_id - self.index = index - - @classmethod - def from_inline(cls, inline): - data = InputSource.re_inline.match(inline) - if data is None: - raise MalformedDocumentError("Inline input") - if data.group(1): - source = data.group(1) - origin_id = data.group(2) - index = int(data.group(3)) - else: - source = data.group(4) - origin_id = data.group(5) - index = int(data.group(6)) - return cls(source, origin_id, index) - - def inline(self): - return "{0}:{1}:{2}".format(self.source, - self.origin_id, - self.index) - - -class UnlockParameter: - - def __init__(self): - pass - - @classmethod - def from_parameter(cls, parameter): - for params_type in (SIGParameter, XHXParameter): - param = params_type.from_parameter(parameter) - if param: - return param - - def compute(self): - pass - - -class SIGParameter: - """ - A Transaction UNLOCK SIG parameter - """ - re_sig = re.compile("SIG\(([0-9]+)\)") - - def __init__(self, index): - self.index = index - - @classmethod - def from_parameter(cls, parameter): - sig = SIGParameter.re_sig.match(parameter) - if sig: - return SIGParameter(sig.group(1)) - else: - return None - - def __str__(self): - return "SIG({0})".format(self.index) - - -class XHXParameter: - """ - A Transaction UNLOCK XHX parameter - """ - re_xhx = re.compile("XHX\(([0-9]+)\)") - - def __init__(self, integer): - self.integer = integer - - @classmethod - def from_parameter(cls, parameter): - xhx = XHXParameter.re_xhx.match(parameter) - if xhx: - return XHXParameter(xhx.group(1)) - else: - return None - - def compute(self): - return - - def __str__(self): - return "XHX({0})".format(self.integer) - - -class Unlock: - """ - A Transaction UNLOCK - """ - re_inline = re.compile("([0-9]+):((?:SIG\([0-9]+\)|XHX\([0-9]+\)|\s)+)\n") - - def __init__(self, index, parameters): - self.index = index - self.parameters = parameters - - @classmethod - def from_inline(cls, inline): - data = Unlock.re_inline.match(inline) - if data is None: - raise MalformedDocumentError("Inline input") - index = int(data.group(1)) - parameters_str = data.group(2).split(' ') - parameters = [] - for p in parameters_str: - param = UnlockParameter.from_parameter(p) - if param: - parameters.append(param) - return cls(index, parameters) - - def inline(self): - return "{0}:{1}".format(self.index, ' '.join([str(p) for p in self.parameters])) - - -class OutputSource: - """ - A Transaction OUTPUT - """ - re_inline = re.compile("([0-9]+):([0-9]+):([A-Za-z0-9\(\)\s]+)\n") - - def __init__(self, amount, base, conditions): - self.amount = amount - self.base = base - self.conditions = conditions - - @classmethod - def from_inline(cls, inline): - data = OutputSource.re_inline.match(inline) - if data is None: - raise MalformedDocumentError("Inline output") - amount = int(data.group(1)) - base = int(data.group(2)) - try: - conditions = pypeg2.parse(data.group(3), output.Condition) - except SyntaxError: - raise MalformedDocumentError("Output source syntax error") - return cls(amount, base, conditions) - - def inline(self): - return "{0}:{1}:{2}".format(self.amount, self.base, - pypeg2.compose(self.conditions, output.Condition)) diff --git a/ucoinpy/grammars/__init__.py b/ucoinpy/grammars/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/ucoinpy/grammars/output.py b/ucoinpy/grammars/output.py deleted file mode 100644 index 183543d070ae88f38c1f871e87712a02a4ccc0d0..0000000000000000000000000000000000000000 --- a/ucoinpy/grammars/output.py +++ /dev/null @@ -1,83 +0,0 @@ -from ..documents.constants import pubkey_regex -from ..documents.constants import block_hash_regex as hash_regex -from pypeg2 import * - - -class Pubkey(str): - regex = re.compile(pubkey_regex) - - -class Hash(str): - regex = re.compile(hash_regex) - - -class SIG(str): - grammar = "SIG(", attr('pubkey', Pubkey), ")" - - @classmethod - def token(cls, pubkey): - sig = cls() - sig.pubkey = pubkey - return sig - - def compose(self, parser, grammar=None, attr_of=None): - return "SIG({0})".format(self.pubkey) - - -class XHX(str): - grammar = "XHX(", attr('sha_hash', Hash), ")" - - @classmethod - def token(cls, sha_hash): - xhx = cls() - xhx.sha_hash = sha_hash - return xhx - - def compose(self, parser, grammar=None, attr_of=None): - return "XHX({0})".format(self.sha_hash) - - -class Operator(Keyword): - grammar = Enum(K("AND"), K("OR")) - - @classmethod - def token(cls, keyword): - op = cls(keyword) - return op - - def compose(self, parser, grammar=None, attr_of=None): - return "{0}".format(self.name) - - -class Condition(str): - @classmethod - def token(cls, left, op=None, right=None): - condition = cls() - condition.left = left - if op: - condition.op = op - if right: - condition.right = right - return condition - - def compose(self, parser, grammar=None, attr_of=None): - if type(self.left) is Condition: - left = "({0})".format(parser.compose(self.left, grammar=grammar, attr_of=attr_of)) - else: - left = parser.compose(self.left, grammar=grammar, attr_of=attr_of) - - if getattr(self, 'op', None): - - if type(self.right) is Condition: - right = "({0})".format(parser.compose(self.right, grammar=grammar, attr_of=attr_of)) - else: - right = parser.compose(self.right, grammar=grammar, attr_of=attr_of) - op = parser.compose(self.op, grammar=grammar, attr_of=attr_of) - result = "{0} {1} {2}".format(left, op, right) - else: - result = left - return result - -Condition.grammar = contiguous(attr('left', [SIG, XHX, ('(', Condition, ')')]), - maybe_some(whitespace, attr('op', Operator), whitespace, - attr('right', [SIG, XHX, ('(', Condition, ')')]))) diff --git a/ucoinpy/key/__init__.py b/ucoinpy/key/__init__.py deleted file mode 100644 index dc1b0fae8c00c238ac22aec69822bf13425a5c56..0000000000000000000000000000000000000000 --- a/ucoinpy/key/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .signing_key import SigningKey \ No newline at end of file diff --git a/ucoinpy/key/signing_key.py b/ucoinpy/key/signing_key.py deleted file mode 100644 index d888ce2323642bc2b735385fc24dcced464a2fe5..0000000000000000000000000000000000000000 --- a/ucoinpy/key/signing_key.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Ucoin public and private keys - -@author: inso -""" - -import base58 -import base64 -import libnacl.sign -from pylibscrypt import scrypt - - -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(libnacl.sign.Signer): - 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)