Skip to content
Snippets Groups Projects
Commit e27d101a authored by inso's avatar inso
Browse files

New exception MalformedErrorDocument

parent b964c9df
No related branches found
No related tags found
No related merge requests found
'''
Created on 13 déc. 2014
@author: inso
'''
import unittest
from ucoinpy.documents.status import Status
raw_status = """Version: 1
Type: Status
Currency: beta_brousouf
Status: UP
Block: 8-1922C324ABC4AF7EF7656734A31F5197888DDD52
From: HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
To: 8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU
dkaXIiCYUJtCg8Feh/BKvPYf4uFH9CJ/zY6J4MlA9BsjmcMe4YAblvNt/gJy31b1aGq3ue3h14mLMCu84rraDg==
"""
class Test_Status(unittest.TestCase):
def test_fromraw(self):
status = Status.from_signed_raw(raw_status)
self.assertEqual(status.status, 'UP')
self.assertEqual(status.blockid, "8-1922C324ABC4AF7EF7656734A31F5197888DDD52")
self.assertEqual(status.sender, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(status.recipient, "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU")
self.assertEqual(status.signatures[0], "dkaXIiCYUJtCg8Feh/BKvPYf4uFH9CJ/zY6J4MlA9BsjmcMe4YAblvNt/gJy31b1aGq3ue3h14mLMCu84rraDg==")
def test_fromraw_toraw(self):
status = Status.from_signed_raw(raw_status)
rendered_status = status.signed_raw()
from_rendered_status = Status.from_signed_raw(rendered_status)
self.assertEqual(from_rendered_status.status, 'UP')
self.assertEqual(from_rendered_status.blockid, "8-1922C324ABC4AF7EF7656734A31F5197888DDD52")
self.assertEqual(from_rendered_status.sender, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(from_rendered_status.recipient, "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU")
self.assertEqual(from_rendered_status.signatures[0], "dkaXIiCYUJtCg8Feh/BKvPYf4uFH9CJ/zY6J4MlA9BsjmcMe4YAblvNt/gJy31b1aGq3ue3h14mLMCu84rraDg==")
......@@ -21,7 +21,7 @@ PROTOCOL_VERSION="1"
MANAGED_API=["BASIC_MERKLED_API"]
__author__ = 'Caner Candan & inso'
__version__ = '0.14.2'
__version__ = '0.14.3'
__nonsense__ = 'uCoin'
from . import api, documents, key
\ No newline at end of file
......@@ -2,6 +2,5 @@ from .block import Block, BlockId
from .certification import SelfCertification, Certification
from .membership import Membership
from .peer import Endpoint, BMAEndpoint, UnknownEndpoint, Peer
from .status import Status
from .transaction import SimpleTransaction, Transaction
from .document import Document
\ No newline at end of file
from .document import Document, MalformedDocumentError
\ No newline at end of file
from .document import Document
from .document import Document, MalformedDocumentError
from .certification import SelfCertification, Certification
from .membership import Membership
from .transaction import Transaction
......@@ -28,6 +28,8 @@ class BlockId:
:param str blockid: The block id
"""
data = blockid.split("-")
if len(data) != 2:
raise MalformedDocumentError('BlockId')
number = int(data[0])
sha_hash = data[1]
return cls(number, sha_hash)
......@@ -107,6 +109,28 @@ The class Block handles Block documents.
re_certifications = re.compile("Certifications:\n")
re_transactions = re.compile("Transactions:\n")
fields_parsers = {**Document.fields_parsers, **{
'Type': re_type,
'Noonce': re_noonce,
'Number': re_number,
'PoWMin': re_powmin,
'Time': re_time,
'MedianTime': re_mediantime,
'UD': re_universaldividend,
'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,
'Certifications': re_certifications,
'Transactions': re_transactions
}
}
Empty_Hash = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
def __init__(self, version, currency, noonce, number, powmin, time,
......@@ -167,54 +191,54 @@ The class Block handles Block documents.
lines = raw.splitlines(True)
n = 0
version = int(Block.re_version.match(lines[n]).group(1))
n = n + 1
version = int(Block.parse_field("Version", lines[n]))
n += 1
Block.re_type.match(lines[n]).group(1)
n = n + 1
Block.parse_field("Type", lines[n])
n += 1
currency = Block.re_currency.match(lines[n]).group(1)
n = n + 1
currency = Block.parse_field("Currency", lines[n])
n += 1
noonce = int(Block.re_noonce.match(lines[n]).group(1))
n = n + 1
noonce = int(Block.parse_field("Noonce", lines[n]))
n += 1
number = int(Block.re_number.match(lines[n]).group(1))
n = n + 1
number = int(Block.parse_field("Number", lines[n]))
n += 1
powmin = int(Block.re_powmin.match(lines[n]).group(1))
n = n + 1
powmin = int(Block.parse_field("PoWMin", lines[n]))
n += 1
time = int(Block.re_time.match(lines[n]).group(1))
n = n + 1
time = int(Block.parse_field("Time", lines[n]))
n += 1
mediantime = int(Block.re_mediantime.match(lines[n]).group(1))
n = n + 1
mediantime = int(Block.parse_field("MedianTime", lines[n]))
n += 1
ud = Block.re_universaldividend.match(lines[n])
if ud is not None:
ud = int(ud.group(1))
n = n + 1
n += 1
issuer = Block.re_issuer.match(lines[n]).group(1)
n = n + 1
issuer = Block.parse_field("Issuer", lines[n])
n += 1
prev_hash = None
prev_issuer = None
if number > 0:
prev_hash = Block.re_previoushash.match(lines[n]).group(1)
n = n + 1
prev_hash = Block.parse_field("PreviousHash", lines[n])
n += 1
prev_issuer = Block.re_previousissuer.match(lines[n]).group(1)
n = n + 1
prev_issuer = Block.parse_field("PreviousIssuer", lines[n])
n += 1
parameters = None
if number == 0:
parameters = Block.re_parameters.match(lines[n]).groups()
n = n + 1
n += 1
members_count = int(Block.re_memberscount.match(lines[n]).group(1))
n = n + 1
members_count = int(Block.parse_field("MembersCount", lines[n]))
n += 1
identities = []
joiners = []
......@@ -225,50 +249,50 @@ The class Block handles Block documents.
transactions = []
if Block.re_identities.match(lines[n]) is not None:
n = n + 1
n += 1
while Block.re_joiners.match(lines[n]) is None:
selfcert = SelfCertification.from_inline(version, currency, lines[n])
identities.append(selfcert)
n = n + 1
n += 1
if Block.re_joiners.match(lines[n]):
n = n + 1
n += 1
while Block.re_actives.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "IN", lines[n])
joiners.append(membership)
n = n + 1
n += 1
if Block.re_actives.match(lines[n]):
n = n + 1
n += 1
while Block.re_leavers.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "IN", lines[n])
actives.append(membership)
n = n + 1
n += 1
if Block.re_leavers.match(lines[n]):
n = n + 1
n += 1
while Block.re_excluded.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "OUT", lines[n])
leavers.append(membership)
n = n + 1
n += 1
if Block.re_excluded.match(lines[n]):
n = n + 1
n += 1
while Block.re_certifications.match(lines[n]) is None:
membership = Block.re_exclusion.match(lines[n]).group(1)
excluded.append(membership)
n = n + 1
n += 1
if Block.re_certifications.match(lines[n]):
n = n + 1
n += 1
while Block.re_transactions.match(lines[n]) is None:
certification = Certification.from_inline(version, currency,
prev_hash, lines[n])
certifications.append(certification)
n = n + 1
n += 1
if Block.re_transactions.match(lines[n]):
n = n + 1
n += 1
while not Block.re_signature.match(lines[n]):
tx_lines = ""
header_data = Transaction.re_header.match(lines[n])
......@@ -280,11 +304,11 @@ The class Block handles Block documents.
tx_max = n + issuers_num * 2 + inputs_num + outputs_num + has_comment + 1
for i in range(n, tx_max):
tx_lines += lines[n]
n = n + 1
n += 1
transaction = Transaction.from_compact(currency, tx_lines)
transactions.append(transaction)
signature = Block.re_signature.match(lines[n]).group(1)
signature = Block.parse_field("Signature", lines[n])
return cls(version, currency, noonce, number, powmin, time,
mediantime, ud, issuer, prev_hash, prev_issuer,
......
......@@ -2,7 +2,7 @@ import re
import base64
import logging
from .document import Document
from .document import Document, MalformedDocumentError
class SelfCertification(Document):
......@@ -26,6 +26,8 @@ class SelfCertification(Document):
@classmethod
def from_inline(cls, version, currency, inline):
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 = int(selfcert_data.group(3))
......@@ -63,6 +65,8 @@ class Certification(Document):
@classmethod
def from_inline(cls, version, currency, blockhash, inline):
cert_data = Certification.re_inline.match(inline)
if cert_data is None:
raise MalformedDocumentError("Certification")
pubkey_from = cert_data.group(1)
pubkey_to = cert_data.group(2)
blocknumber = int(cert_data.group(3))
......
import base58
import base64
import re
import logging
import hashlib
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("([A-Za-z0-9+/]+(?:=|==)?)\n")
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):
self.version = version
self.currency = currency
......
......@@ -3,7 +3,7 @@ Created on 2 déc. 2014
@author: inso
"""
from .document import Document
from .document import Document, MalformedDocumentError
import re
......@@ -28,11 +28,20 @@ class Membership(Document):
([0-9]+):([0-9a-fA-F]{5,40}):([0-9]+):([^\n]+)\n")
re_type = re.compile("Type: (Membership)")
re_issuer = re.compile("Issuer: ([1-9A-Za-z][^OIl]{42,45})\n")
re_block = re.compile("Block: ([0-9]+)-([0-9a-fA-F]{5,40})\n")
re_block = re.compile("Block: ([0-9]+-[0-9a-fA-F]{5,40})\n")
re_membership_type = re.compile("Membership: (IN|OUT)")
re_userid = re.compile("UserID: ([^\n]+)\n")
re_certts = re.compile("CertTS: ([0-9]+)\n")
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, blockid,
membership_type, uid, cert_ts, signature):
"""
......@@ -48,6 +57,8 @@ class Membership(Document):
@classmethod
def from_inline(cls, version, currency, membership_type, inline):
data = Membership.re_inline.match(inline)
if data is None:
raise MalformedDocumentError("Inline membership")
issuer = data.group(1)
signature = data.group(2)
block_number = int(data.group(3))
......@@ -59,40 +70,38 @@ class Membership(Document):
@classmethod
def from_signed_raw(cls, raw, signature=None):
from .block import BlockId
lines = raw.splitlines(True)
n = 0
version = int(Membership.re_version.match(lines[n]).group(1))
n = n + 1
version = int(Membership.parse_field("Version", lines[n]))
n += 1
Membership.re_type.match(lines[n]).group(1)
n = n + 1
Membership.parse_field("Type", lines[n])
n += 1
currency = Membership.re_currency.match(lines[n]).group(1)
n = n + 1
currency = Membership.parse_field("Currency", lines[n])
n += 1
issuer = Membership.re_issuer.match(lines[n]).group(1)
n = n + 1
issuer = Membership.parse_field("Issuer", lines[n])
n += 1
blockid = Membership.re_block.match(lines[n])
blocknumber = int(blockid.group(1))
blockhash = blockid.group(2)
n = n + 1
blockid = BlockId.from_str(Membership.parse_field("Block", lines[n]))
n += 1
membership_type = Membership.re_membership_type.match(lines[n]).group(1)
n = n + 1
membership_type = Membership.parse_field("Membership", lines[n])
n += 1
uid = Membership.re_userid.match(lines[n]).group(1)
n = n + 1
uid = Membership.parse_field("UserID", lines[n])
n += 1
cert_ts = int(Membership.re_certts.match(lines[n]).group(1))
n = n + 1
cert_ts = int(Membership.parse_field("CertTS", lines[n]))
n += 1
signature = Membership.re_signature.match(lines[n]).group(1)
n = n + 1
signature = Membership.parse_field("Signature", lines[n])
n += 1
from .block import BlockId
return cls(version, currency, issuer, BlockId(blocknumber, blockhash),
return cls(version, currency, issuer, blockid,
membership_type, uid, cert_ts, signature)
def raw(self):
......
import re
from ..api.bma import ConnectionHandler
from .document import Document
from .document import Document, MalformedDocumentError
from . import BlockId
from .. import PROTOCOL_VERSION, MANAGED_API
......@@ -26,7 +26,14 @@ class Peer(Document):
re_type = re.compile("Type: (Peer)")
re_pubkey = re.compile("PublicKey: ([1-9A-Za-z][^OIl]{42,45})\n")
re_block = re.compile("Block: ([0-9]+-[0-9a-fA-F]{5,40})\n")
re_endpoints = re.compile("Endpoints:\n")
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, blockid,
endpoints, signature):
......@@ -41,29 +48,29 @@ class Peer(Document):
lines = raw.splitlines(True)
n = 0
version = int(Peer.re_version.match(lines[n]).group(1))
n = n + 1
version = int(Peer.parse_field("Version", lines[n]))
n += 1
Peer.re_type.match(lines[n]).group(1)
n = n + 1
Peer.parse_field("Type", lines[n])
n += 1
currency = Peer.re_currency.match(lines[n]).group(1)
n = n + 1
currency = Peer.parse_field("Currency", lines[n])
n += 1
pubkey = Peer.re_pubkey.match(lines[n]).group(1)
n = n + 1
pubkey = Peer.parse_field("Pubkey", lines[n])
n += 1
blockid = BlockId.from_str(Peer.re_block.match(lines[n]).group(1))
n = n + 1
blockid = BlockId.from_str(Peer.parse_field("Block", lines[n]))
n += 1
Peer.re_endpoints.match(lines[n])
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 = n + 1
n += 1
signature = Peer.re_signature.match(lines[n]).group(1)
......@@ -123,6 +130,8 @@ class BMAEndpoint(Endpoint):
@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)
......
import re
from .document import Document
class Status(Document):
"""
.. note:: A status document is specified by the following format :
| Version: VERSION
| Type: Status
| Currency: CURRENCY_NAME
| Status: STATUS
| Block: BLOCK
| From: SENDER
| To: RECIPIENT
"""
re_type = re.compile("Type: (Status)")
re_status = re.compile("Status: (NEW|NEW_BACK|UP|UP_BACK|DOWN)")
re_block = re.compile("Block: ([0-9]+-[0-9a-fA-F]{5,40})\n")
re_from = re.compile("From: ([1-9A-Za-z][^OIl]{42,45})\n")
re_to = re.compile("To: ([1-9A-Za-z][^OIl]{42,45})\n")
def __init__(self, version, currency, status, blockid, sender,
recipient, signature):
"""
Constructor
"""
super().__init__(version, currency, [signature])
self.status = status
self.blockid = blockid
self.sender = sender
self.recipient = recipient
@classmethod
def from_signed_raw(cls, raw):
lines = raw.splitlines(True)
n = 0
version = int(Status.re_version.match(lines[n]).group(1))
n = n + 1
Status.re_type.match(lines[n]).group(1)
n = n + 1
currency = Status.re_currency.match(lines[n]).group(1)
n = n + 1
status = Status.re_status.match(lines[n]).group(1)
n = n + 1
blockid = Status.re_block.match(lines[n]).group(1)
n = n + 1
sender = Status.re_from.match(lines[n]).group(1)
n = n + 1
recipient = Status.re_to.match(lines[n]).group(1)
n = n + 1
signature = Status.re_signature.match(lines[n]).group(1)
n = n + 1
return cls(version, currency, status, blockid,
sender, recipient, signature)
def raw(self):
return """Version: {0}
Type: Status
Currency: {1}
Status: {2}
Block: {3}
From: {4}
To: {5}
""".format(self.version, self.currency, self.status,
self.blockid, self.sender, self.recipient)
from .document import Document
from .document import Document, MalformedDocumentError
import re
import logging
class Transaction(Document):
......@@ -47,6 +46,18 @@ class Transaction(Document):
re_comment = re.compile("Comment: ([^\n]*)\n")
re_pubkey = re.compile("([1-9A-Za-z][^OIl]{42,45})\n")
fields_parsers = {**Document.fields_parsers, **{
"Type": re_type,
"TX": re_header,
"Issuers": re_issuers,
"Inputs": re_inputs,
"Outputs": re_outputs,
"Comment": re_comment,
"Compact comment": re_compact_comment,
"Pubkey": re_pubkey
}
}
def __init__(self, version, currency, issuers, inputs, outputs,
comment, signatures):
"""
......@@ -65,40 +76,42 @@ class Transaction(Document):
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))
outputs_num = int(header_data.group(4))
has_comment = int(header_data.group(5))
n = n + 1
n += 1
issuers = []
inputs = []
outputs = []
signatures = []
for i in range(0, issuers_num):
issuer = Transaction.re_pubkey.match(lines[n]).group(1)
issuer = Transaction.parse_field("Pubkey", lines[n])
issuers.append(issuer)
n = n + 1
n += 1
for i in range(0, inputs_num):
input_source = InputSource.from_inline(lines[n])
inputs.append(input_source)
n = n + 1
n += 1
for i in range(0, outputs_num):
output_source = OutputSource.from_inline(lines[n])
outputs.append(output_source)
n = n + 1
n += 1
comment = ""
if has_comment == 1:
comment = Transaction.re_compact_comment.match(lines[n]).group(1)
n = n + 1
n += 1
while n < len(lines):
signatures.append(Transaction.re_signature.match(lines[n]).group(1))
n = n + 1
n += 1
return cls(version, currency, issuers, inputs, outputs, comment, signatures)
......@@ -107,14 +120,14 @@ class Transaction(Document):
lines = raw.splitlines(True)
n = 0
version = int(Transaction.re_version.match(lines[n]).group(1))
n = n + 1
version = int(Transaction.parse_field("Version", lines[n]))
n += 1
Transaction.re_type.match(lines[n]).group(1)
n = n + 1
Transaction.parse_field("Type", lines[n])
n += 1
currency = Transaction.re_currency.match(lines[n]).group(1)
n = n + 1
currency = Transaction.parse_field("Currency", lines[n])
n += 1
issuers = []
inputs = []
......@@ -122,34 +135,34 @@ class Transaction(Document):
signatures = []
if Transaction.re_issuers.match(lines[n]):
n = n + 1
n += 1
while Transaction.re_inputs.match(lines[n]) is None:
issuer = Transaction.re_pubkey.match(lines[n]).group(1)
issuer = Transaction.parse_field("Pubkey", lines[n])
issuers.append(issuer)
n = n + 1
n += 1
if Transaction.re_inputs.match(lines[n]):
n = n + 1
n += 1
while Transaction.re_outputs.match(lines[n]) is None:
input_source = InputSource.from_inline(lines[n])
inputs.append(input_source)
n = n + 1
n += 1
if Transaction.re_outputs.match(lines[n]) is not None:
n = n + 1
n += 1
while not Transaction.re_comment.match(lines[n]):
output = OutputSource.from_inline(lines[n])
outputs.append(output)
n = n + 1
n += 1
comment = Transaction.re_comment.match(lines[n]).group(1)
n = 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.re_signature.match(lines[n]).group(1)
sign = Transaction.parse_field("Signature", lines[n])
signatures.append(sign)
n = n + 1
n += 1
return cls(version, currency, issuers, inputs, outputs,
comment, signatures)
......@@ -245,6 +258,8 @@ class InputSource:
@classmethod
def from_inline(cls, inline):
data = InputSource.re_inline.match(inline)
if data is None:
raise MalformedDocumentError("Inline input")
index = int(data.group(1))
source = data.group(2)
number = int(data.group(3))
......@@ -282,6 +297,8 @@ class OutputSource():
@classmethod
def from_inline(cls, inline):
data = OutputSource.re_inline.match(inline)
if data is None:
raise MalformedDocumentError("Inline output")
pubkey = data.group(1)
amount = int(data.group(2))
return cls(pubkey, amount)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment