diff --git a/duniterpy/api/constants.py b/duniterpy/api/constants.py deleted file mode 100644 index 4ca0a4d93be336a1f7451b9addc84e07a2c311d4..0000000000000000000000000000000000000000 --- a/duniterpy/api/constants.py +++ /dev/null @@ -1,20 +0,0 @@ - -uid_regex = "[A-Za-z0-9_-]{2,100}" -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}" -hash_regex = "[A-F0-9]{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) -conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*"\ - .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex) -ipv4_regex = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' -ipv6_regex = '(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){,6}[0-9A-Fa-f]{1,4})?::)(?:%.+)?' -ws2pid_regex = "[0-9a-f]{8}" -host_regex = "[a-z0-9-_.]*(?:.[a-zA-Z])?" -path_regex = "[/\w \.-]*/?" -ws2p_private_prefix_regex = "O[CT][SAM]" -ws2p_public_prefix_regex = "I[CT]" -ws2p_head_regex = "HEAD:?(?:[0-9]+)?" diff --git a/duniterpy/api/endpoint.py b/duniterpy/api/endpoint.py index 6d7bec8a98d2ef36f8805e3b7b8ebf8364b47e5e..1b205979d439750f6dc29768dbcad0d003ae85a3 100644 --- a/duniterpy/api/endpoint.py +++ b/duniterpy/api/endpoint.py @@ -2,7 +2,7 @@ import re import aiohttp -from .constants import * +from ..constants import * from ..documents import MalformedDocumentError diff --git a/duniterpy/constants.py b/duniterpy/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..7e6b875e67a6fbc3aaa4073387ebec2e89a692b3 --- /dev/null +++ b/duniterpy/constants.py @@ -0,0 +1,35 @@ +uid_regex = "[A-Za-z0-9_-]{2,100}" +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}" +hash_regex = "[A-F0-9]{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) +conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*" \ + .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex) +ipv4_regex = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][' \ + '0-9]|25[0-5])' +ipv6_regex = '(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[' \ + '0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,' \ + '4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){' \ + '3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,' \ + '4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){' \ + '3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,' \ + '4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[' \ + '0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,' \ + '2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][' \ + '0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[' \ + '0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,' \ + '4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][' \ + '0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,' \ + '4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][' \ + '0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,' \ + '4}:){,6}[0-9A-Fa-f]{1,4})?::)(?:%.+)?' +ws2pid_regex = "[0-9a-f]{8}" +host_regex = "[a-z0-9-_.]*(?:.[a-zA-Z])?" +path_regex = "[/\w \.-]*/?" +ws2p_private_prefix_regex = "O[CT][SAM]" +ws2p_public_prefix_regex = "I[CT]" +ws2p_head_regex = "HEAD:?(?:[0-9]+)?" diff --git a/duniterpy/documents/__init__.py b/duniterpy/documents/__init__.py index 29f7818a822fd811521c7ec63ccb9e041d42858c..36c64af8e95a4b74ee497df8be9a8632ddf029d5 100644 --- a/duniterpy/documents/__init__.py +++ b/duniterpy/documents/__init__.py @@ -5,5 +5,3 @@ from .transaction import SimpleTransaction, Transaction, InputSource, OutputSour SIGParameter, Unlock, UnlockParameter from .document import Document, MalformedDocumentError from .crc_pubkey import CRCPubkey - -from . import constants diff --git a/duniterpy/documents/block.py b/duniterpy/documents/block.py index 99f9c96233ce80cc652128419df62079a3b3d971..8606000f4c9c18a17244f1a00c0645aeca4a8cc1 100644 --- a/duniterpy/documents/block.py +++ b/duniterpy/documents/block.py @@ -1,12 +1,12 @@ -from .document import Document, MalformedDocumentError +import base64 +import hashlib +import re + from .certification import Identity, Certification, Revocation +from .document import Document, MalformedDocumentError from .membership import Membership from .transaction import Transaction -from .constants import pubkey_regex, block_id_regex, block_hash_regex - -import re -import hashlib -import base64 +from ..constants import pubkey_regex, block_id_regex, block_hash_regex def block_uid(value): @@ -25,7 +25,7 @@ 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)) + block_hash_regex=block_hash_regex)) re_hash = re.compile("({block_hash_regex})".format(block_hash_regex=block_hash_regex)) @classmethod @@ -33,8 +33,8 @@ class BlockUID: 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) + assert (type(number) is int) + assert (BlockUID.re_hash.match(sha_hash) is not None) self.number = number self.sha_hash = sha_hash @@ -158,33 +158,33 @@ The class Block handles Block documents. 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, - 'IssuersFrame': re_issuers_frame, - 'IssuersFrameVar': re_issuers_frame_var, - 'DifferentIssuersCount': re_different_issuers_count, - '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, - } - } + 'Type': re_type, + 'Number': re_number, + 'PoWMin': re_powmin, + 'Time': re_time, + 'MedianTime': re_mediantime, + 'UD': re_universaldividend, + 'UnitBase': re_unitbase, + 'Issuer': re_issuer, + 'IssuersFrame': re_issuers_frame, + 'IssuersFrameVar': re_issuers_frame_var, + 'DifferentIssuersCount': re_different_issuers_count, + '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" @@ -205,12 +205,12 @@ The class Block handles Block documents. :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 int issuers__frame: + :param int issuers_frame: :param int issuers_frame_var: :param int different_issuers_count: the count of issuers :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 Optional[Sequence[str]] 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[duniterpy.documents.Identity] identities: the self certifications declared in this block :param list[duniterpy.documents.Membership] joiners: the joiners memberships via "IN" documents @@ -223,16 +223,17 @@ The class Block handles Block documents. :param list[duniterpy.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 + :param str signature: the block signature """ super().__init__(version, currency, [signature]) documents_versions = max(max([1] + [i.version for i in identities]), - max([1] + [m.version for m in actives + leavers + joiners]), - max([1] + [r.version for r in revokations]), - max([1] + [c.version for c in certifications]), - max([1] + [t.version for t in transactions])) + max([1] + [m.version for m in actives + leavers + joiners]), + max([1] + [r.version for r in revokations]), + max([1] + [c.version for c in certifications]), + max([1] + [t.version for t in transactions])) if self.version < documents_versions: - raise MalformedDocumentError("Block version is too low : {0} < {1}".format(self.version, documents_versions)) + raise MalformedDocumentError( + "Block version is too low : {0} < {1}".format(self.version, documents_versions)) self.number = number self.powmin = powmin self.time = time @@ -261,7 +262,7 @@ The class Block handles Block documents. @property def blockUID(self): return BlockUID(self.number, self.proof_of_work()) - + @classmethod def from_signed_raw(cls, signed_raw): lines = signed_raw.splitlines(True) @@ -445,11 +446,11 @@ 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) + 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) diff --git a/duniterpy/documents/certification.py b/duniterpy/documents/certification.py index e4276691c2c7ac2cf45529ed8f2763e241ca3f96..342ba3a773abe20590ec4ecaae495d6096fac150 100644 --- a/duniterpy/documents/certification.py +++ b/duniterpy/documents/certification.py @@ -1,9 +1,9 @@ -import re import base64 import logging +import re +from ..constants import pubkey_regex, signature_regex, block_id_regex, block_uid_regex, uid_regex from .document import Document, MalformedDocumentError -from .constants import pubkey_regex, signature_regex, block_id_regex, block_uid_regex, uid_regex class Identity(Document): @@ -118,11 +118,11 @@ class Certification(Document): """ 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 - )) + 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)) re_type = re.compile("Type: (Certification)") re_issuer = re.compile("Issuer: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) @@ -207,7 +207,7 @@ class Certification(Document): :param inline: :return: """ - from .block import Block, BlockUID + from .block import BlockUID cert_data = Certification.re_inline.match(inline) if cert_data is None: raise MalformedDocumentError("Certification ({0})".format(inline)) @@ -273,9 +273,9 @@ class Revocation(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 - )) + pubkey_regex=pubkey_regex, + signature_regex=signature_regex + )) re_type = re.compile("Type: (Revocation)") re_issuer = re.compile("Issuer: ({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) @@ -304,8 +304,7 @@ class Revocation(Document): From inline version in block :param int version: :param str currency: - :param str pubkey: - :param str signature: + :param str inline: :return: """ cert_data = Revocation.re_inline.match(inline) diff --git a/duniterpy/documents/constants.py b/duniterpy/documents/constants.py deleted file mode 100644 index 4ca0a4d93be336a1f7451b9addc84e07a2c311d4..0000000000000000000000000000000000000000 --- a/duniterpy/documents/constants.py +++ /dev/null @@ -1,20 +0,0 @@ - -uid_regex = "[A-Za-z0-9_-]{2,100}" -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}" -hash_regex = "[A-F0-9]{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) -conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*"\ - .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex) -ipv4_regex = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' -ipv6_regex = '(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){,6}[0-9A-Fa-f]{1,4})?::)(?:%.+)?' -ws2pid_regex = "[0-9a-f]{8}" -host_regex = "[a-z0-9-_.]*(?:.[a-zA-Z])?" -path_regex = "[/\w \.-]*/?" -ws2p_private_prefix_regex = "O[CT][SAM]" -ws2p_public_prefix_regex = "I[CT]" -ws2p_head_regex = "HEAD:?(?:[0-9]+)?" diff --git a/duniterpy/documents/crc_pubkey.py b/duniterpy/documents/crc_pubkey.py index 41555777ffc8adf417c63e9abeb476aec3e4ae55..616cc29fa29446a9fabc298eb44e3c400b854a90 100644 --- a/duniterpy/documents/crc_pubkey.py +++ b/duniterpy/documents/crc_pubkey.py @@ -1,7 +1,7 @@ import base58 import re import hashlib -from .constants import pubkey_regex +from ..constants import pubkey_regex from ..helpers import ensure_str @@ -20,8 +20,8 @@ class CRCPubkey: self.crc = crc @classmethod - def from_str(cls, str): - data = CRCPubkey.re_crc_pubkey.match(str) + def from_str(cls, crc_pubkey): + data = CRCPubkey.re_crc_pubkey.match(crc_pubkey) pubkey = data.group(1) crc = data.group(2) return cls(pubkey, crc) @@ -41,4 +41,4 @@ class CRCPubkey: return CRCPubkey.from_pubkey(self.pubkey).crc == self.crc def __str__(self): - return "{:}:{:}".format(self.pubkey, self.crc) \ No newline at end of file + return "{:}:{:}".format(self.pubkey, self.crc) diff --git a/duniterpy/documents/document.py b/duniterpy/documents/document.py index 51de8094851b8cdaa52e6fc808a154a3dcebed06..cbd4a750da88060021511f7277249b309bab7160 100644 --- a/duniterpy/documents/document.py +++ b/duniterpy/documents/document.py @@ -1,14 +1,16 @@ import base64 -import re -import logging import hashlib -from .constants import signature_regex +import logging +import re + +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)) @@ -65,7 +67,7 @@ class Document: """ raise NotImplementedError() - def signed_raw(self): + def signed_raw(self, *args): """ If keys are None, returns the raw + current signatures If keys are present, returns the raw signed by these keys diff --git a/duniterpy/documents/membership.py b/duniterpy/documents/membership.py index 26e09f47627a06f29def3df3a0b02fe4c4ac3523..24bcea77ce2e0d72eb0b04d7445f52c067968d0a 100644 --- a/duniterpy/documents/membership.py +++ b/duniterpy/documents/membership.py @@ -3,11 +3,11 @@ 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 +from .document import Document, MalformedDocumentError +from ..constants import block_uid_regex, signature_regex, pubkey_regex + class Membership(Document): """ @@ -25,10 +25,11 @@ class Membership(Document): """ # 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_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)) @@ -125,16 +126,16 @@ Membership: {4} UserID: {5} CertTS: {6} """.format(self.version, - self.currency, - self.issuer, - self.membership_ts, - self.membership_type, - self.uid, - self.identity_ts) + 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) + self.signatures[0], + self.membership_ts, + self.identity_ts, + self.uid) diff --git a/duniterpy/documents/peer.py b/duniterpy/documents/peer.py index 60255e123109de1c9862d999896be8c3d6fea017..408f847ac0e39daf049edc0d8406973b1bc912ef 100644 --- a/duniterpy/documents/peer.py +++ b/duniterpy/documents/peer.py @@ -3,7 +3,7 @@ import re from duniterpy.api.endpoint import endpoint from .document import Document from . import BlockUID -from .constants import block_hash_regex, pubkey_regex +from ..constants import block_hash_regex, pubkey_regex class Peer(Document): diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py index b79c8f8b73ed92aefd93e46f24d0290534f59911..70f5429652f3d85420ad7d38e078bfc0a9ab33e2 100644 --- a/duniterpy/documents/transaction.py +++ b/duniterpy/documents/transaction.py @@ -1,8 +1,10 @@ +import re + +import pypeg2 + from .document import Document, MalformedDocumentError -from .constants import pubkey_regex, transaction_hash_regex, block_id_regex, block_uid_regex, conditions_regex +from ..constants import pubkey_regex, transaction_hash_regex, block_id_regex, block_uid_regex from ..grammars import output -import pypeg2 -import re def reduce_base(amount, base): @@ -62,7 +64,7 @@ class Transaction(Document): """ 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_header = re.compile("TX:([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([01]):([0-9]+)\n") re_compact_blockstamp = re.compile("({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) re_blockstamp = re.compile("Blockstamp: ({block_uid_regex})\n".format(block_uid_regex=block_uid_regex)) re_locktime = re.compile("Locktime: ([0-9]+)\n") @@ -75,20 +77,20 @@ class Transaction(Document): re_pubkey = re.compile("({pubkey_regex})\n".format(pubkey_regex=pubkey_regex)) fields_parsers = {**Document.fields_parsers, **{ - "Type": re_type, - "Blockstamp": re_blockstamp, - "CompactBlockstamp": re_compact_blockstamp, - "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 - } + "Type": re_type, + "Blockstamp": re_blockstamp, + "CompactBlockstamp": re_compact_blockstamp, + "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, blockstamp, locktime, issuers, inputs, unlocks, outputs, comment, signatures): @@ -127,7 +129,7 @@ class Transaction(Document): for data_list in ('issuers', 'outputs', 'inputs', 'unlocks', 'signatures'): tx_data['multiline_{0}'.format(data_list)] = '\n'.join(tx_data[data_list]) if tx_data["version"] >= 3: - signed_raw = """Version: {version} + signed_raw = """Version: {version} Type: Transaction Currency: {currency} Blockstamp: {blockstamp} @@ -281,8 +283,8 @@ Comment: {comment} 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) + _output = OutputSource.from_inline(lines[n]) + outputs.append(_output) n += 1 comment = Transaction.parse_field("Comment", lines[n]) @@ -344,12 +346,12 @@ 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) + len(self.issuers), + len(self.inputs), + len(self.unlocks), + len(self.outputs), + '1' if self.comment != "" else '0', + self.locktime) if self.version >= 3: doc += "{0}\n".format(self.blockstamp) @@ -374,13 +376,25 @@ class SimpleTransaction(Transaction): As transaction class, but for only one issuer. ... """ - def __init__(self, version, currency, issuer, - single_input, outputs, comment, signature): + + def __init__(self, version, currency, blockstamp, locktime, issuer, + single_input, unlocks, outputs, comment, signature): """ - Constructor + Init instance + + :param version: + :param currency: + :param blockstamp: + :param locktime: + :param issuer: + :param single_input: + :param unlocks: + :param outputs: + :param comment: + :param signature: """ - super().__init__(version, currency, [issuer], [single_input], - outputs, comment, [signature]) + super().__init__(version, currency, blockstamp, locktime, [issuer], [single_input], unlocks, + outputs, comment, [signature]) @staticmethod def is_simple(tx): @@ -421,14 +435,17 @@ class InputSource: 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_inline_v3 = re.compile("([0-9]+):([0-9]+):(?:(?:(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_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_inline_v3 = re.compile( + "([0-9]+):([0-9]+):(?:(?:(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)) def __init__(self, amount, base, source, origin_id, index): """ @@ -481,10 +498,10 @@ class InputSource: self.index) else: return "{0}:{1}:{2}:{3}:{4}".format(self.amount, - self.base, - self.source, - self.origin_id, - self.index) + self.base, + self.source, + self.origin_id, + self.index) class UnlockParameter: @@ -609,4 +626,3 @@ class OutputSource: else: return "{0}:{1}:{2}".format(self.amount, self.base, pypeg2.compose(self.conditions, output.Condition)) - diff --git a/duniterpy/documents/ws2p/heads.py b/duniterpy/documents/ws2p/heads.py index ec272a631736a4e50172c355ab3f86c6476f5b34..7ff2ed7779dc8dfa82964e859051439d44dbb05e 100644 --- a/duniterpy/documents/ws2p/heads.py +++ b/duniterpy/documents/ws2p/heads.py @@ -2,7 +2,7 @@ import attr import re from ..block import BlockUID -from ..constants import ws2p_public_prefix_regex, ws2p_private_prefix_regex,\ +from ...constants import ws2p_public_prefix_regex, ws2p_private_prefix_regex,\ pubkey_regex, signature_regex, ws2pid_regex, block_uid_regex, ws2p_head_regex @@ -170,4 +170,4 @@ class HeadV2: @property def blockstamp(self): - return self.v1.blockstamp \ No newline at end of file + return self.v1.blockstamp diff --git a/duniterpy/grammars/output.py b/duniterpy/grammars/output.py index dd54ba09fc00956158ca0049f0ea037da54892ec..d1870c94ec4728637a6ef52a1f2cd4aee845ad9d 100644 --- a/duniterpy/grammars/output.py +++ b/duniterpy/grammars/output.py @@ -1,7 +1,7 @@ -from ..documents.constants import pubkey_regex -from ..documents.constants import hash_regex from pypeg2 import * +from ..constants import pubkey_regex, hash_regex + class Pubkey(str): regex = re.compile(pubkey_regex) @@ -109,6 +109,7 @@ class Condition(str): result = left return result + Condition.grammar = contiguous(attr('left', [SIG, XHX, CSV, CLTV, ('(', Condition, ')')]), - maybe_some(whitespace, attr('op', Operator), whitespace, - attr('right', [SIG, XHX, CSV, CLTV, ('(', Condition, ')')]))) + maybe_some(whitespace, attr('op', Operator), whitespace, + attr('right', [SIG, XHX, CSV, CLTV, ('(', Condition, ')')]))) diff --git a/tests/documents/test_block.py b/tests/documents/test_block.py index eaa81dd8e52b67e794c7febb5a0199869218ef76..adfd08d07cb12abfd51b1f1c2d66646219d879c5 100644 --- a/tests/documents/test_block.py +++ b/tests/documents/test_block.py @@ -1,9 +1,10 @@ -''' +""" Created on 12 déc. 2014 @author: inso -''' +""" import unittest + from duniterpy.documents.block import Block, BlockUID, block_uid raw_block = """Version: 2 @@ -90,7 +91,6 @@ Nonce: 581 nY/MsFU2luiohLmSiOOimL1RIqbriOBgc22ua03Z2dhxtSJxKZeGNGDvl1jaXgmEBRnXU87yXbZ7ioOS/AAVCA== """ - raw_block_zero = """Version: 10 Type: Block Currency: zeta_brouzouf @@ -138,7 +138,6 @@ Nonce: 2125 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r """ - raw_block_with_leavers = """Version: 2 Type: Block Currency: meta_brouzouf @@ -164,7 +163,6 @@ Nonce: 9906 5LZCFSnm5FkFihPBTpmsPyILEdvu8MXfJOp6OR4d1s+/e2jVWg4J6YSDfO2KBBPgubASyr2QwQuiBlYD2918Bw== """ - raw_block_with_excluded = """Version: 3 Type: Block Currency: test_net @@ -220,7 +218,6 @@ Nonce: 137387 GmgYhWrwCtsK7t2B/omPpxZ8EfJgv9UYzJIFo++Za+A0Mo70xRfZG7kywxbQTTxDk/V7r90P946N89vdVjv1Bg== """ - negative_issuers_frame_var = """Version: 3 Type: Block Currency: test_net @@ -265,7 +262,7 @@ WnJvw204wccmSBQK9UE2rCFw0EG34zf+b58n2KTLwSIhTpgmGsnr5ohkSyYZYcLEKjisLXKNCmMl7D1Q """ -class Test_Block(unittest.TestCase): +class TestBlock(unittest.TestCase): def test_fromraw(self): block = Block.from_signed_raw(raw_block) self.assertEqual(block.version, 2) @@ -297,9 +294,10 @@ class Test_Block(unittest.TestCase): self.assertEqual(block.time, 1418077277) self.assertEqual(block.mediantime, 1418077277) self.assertEqual(block.issuer, "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk") - self.assertEqual(block.parameters, ("0.0488","86400","1000","432000","100","5259600","63115200","5","5259600", - "5259600","0.8","31557600","5","24","300","12","0.67","1488970800", - "1490094000", "15778800")) + self.assertEqual(block.parameters, + ("0.0488", "86400", "1000", "432000", "100", "5259600", "63115200", "5", "5259600", + "5259600", "0.8", "31557600", "5", "24", "300", "12", "0.67", "1488970800", + "1490094000", "15778800")) self.assertEqual(block.members_count, 4) self.assertEqual(len(block.identities), 4) self.assertEqual(len(block.joiners), 4) @@ -438,7 +436,7 @@ class Test_Block(unittest.TestCase): def test_block_uid_converter_error(self): with self.assertRaises(TypeError): - buid = block_uid(1235654) + block_uid(1235654) def test_block_uid_no_convert(self): buid = block_uid(BlockUID(1345, "0000338C775613399FA508A8F8B22EB60F525884730639E2A707299E373F43C0")) @@ -483,7 +481,6 @@ AywstQpC0S5iaA/YQvbz2alpP6zTYG3tjkWpxy1jgeCo028Te2V327bBZbfDGDzsjxOrF4UVmEBiGsgb block_doc = Block.from_signed_raw(block) self.assertEqual(block_doc.proof_of_work(), "00000A84839226046082E2B1AD49664E382D98C845644945D133D4A90408813A") + if __name__ == '__main__': unittest.main() - - diff --git a/tests/grammars/test_output.py b/tests/grammars/test_output.py index b3a1c9506cca05525a2787033c39b6f8497dc88f..2e6a6cee72058b5a8be8271e457249799ea35334 100644 --- a/tests/grammars/test_output.py +++ b/tests/grammars/test_output.py @@ -1,9 +1,11 @@ -from duniterpy.grammars import output import unittest + import pypeg2 +from duniterpy.grammars import output + -class Test_OutputGrammar(unittest.TestCase): +class TestOutputgrammar(unittest.TestCase): def test_sig(self): condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)" result = pypeg2.parse(condition, output.SIG) @@ -34,7 +36,8 @@ class Test_OutputGrammar(unittest.TestCase): self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_simple_and_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(" \ + "309BC5E644F797F53E5A2065EAF38A173437F2E6))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.op.name, "&&") @@ -42,7 +45,8 @@ class Test_OutputGrammar(unittest.TestCase): self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_simple_or_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(" \ + "309BC5E644F797F53E5A2065EAF38A173437F2E6))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.op.name, "||") @@ -50,7 +54,8 @@ class Test_OutputGrammar(unittest.TestCase): self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_complex_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \ + "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.op.name, "||") @@ -70,14 +75,15 @@ class Test_OutputGrammar(unittest.TestCase): self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_instanciate_condition(self): - inst = output.Condition.token(output.SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"), - output.Operator.token("||"), - output.Condition.token( - output.SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"), - output.Operator.token("&&"), - output.XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6") - )) - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" + output.Condition.token(output.SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"), + output.Operator.token("||"), + output.Condition.token( + output.SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"), + output.Operator.token("&&"), + output.XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6") + )) + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \ + "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" inst = pypeg2.parse(condition, output.Condition) self.assertEqual(inst.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(inst.left.op.name, "||")