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

Merge branch 'refactor' of https://github.com/ucoin-io/ucoin-python-api into refactor

Conflicts:
	ucoinpy/documents/block.py
parents a5ec8f73 5ccafe25
Branches
Tags
No related merge requests found
'''
Created on 12 déc. 2014
@author: inso
'''
import pytest
from ucoinpy.documents.block import Block
from mock import Mock
raw_block = "Version: 1\nType: \
Block\nCurrency: zeta_brouzouf\n\
Nonce: 45079\nNumber: 15\nPoWMin: 4\n\
Time: 1418083330\nMedianTime: 1418080208\n\
Issuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk\n\
PreviousHash: 0000E73C340601ACA1AD5AAA5B5E56B03E178EF8\n\
PreviousIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk\n\
MembersCount: 4\nIdentities:\nJoiners:\nActives:\nLeavers:\n\
Excluded:\nCertifications:\nTransactions:\n"
class Test_Block:
def test_fromraw(self):
block = Block.from_raw(raw_block)
assert block.version == 1
assert block.currency == "zeta_brouzouf"
assert block.noonce == 45079
assert block.number == 15
assert block.powmin == 4
assert block.time == 1418083330
assert block.mediantime == 1418080208
assert block.issuer == "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk"
assert block.previoushash == "0000E73C340601ACA1AD5AAA5B5E56B03E178EF8"
assert block.previousissuer == "0000E73C340601ACA1AD5AAA5B5E56B03E178EF8"
assert block.memberscount == 4
assert block.identities == []
assert block.joiners == []
assert block.actives == []
assert block.leavers == []
assert block.excluded == []
assert block.certifications == []
assert block.transactions == []
'''
Created on 6 déc. 2014
@author: inso
'''
import pytest
from ucoinpy.documents.certification import SelfCertification
from ucoinpy.key import Base58Encoder
from mock import Mock
from nacl.signing import SigningKey
uid = "lolcat"
timestamp = 1409990782.24
correct_certification = """UID:lolcat
META:TS:1409990782
J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci
"""
key = SigningKey()
class Test_SelfCertification:
'''
classdocs
'''
def test_certification(self):
cert = SelfCertification(timestamp, uid)
assert cert.signed(key) == correct_certification
...@@ -93,3 +93,59 @@ class Hardship(Blockchain): ...@@ -93,3 +93,59 @@ class Hardship(Blockchain):
def __get__(self, **kwargs): def __get__(self, **kwargs):
assert self.fingerprint is not None assert self.fingerprint is not None
return self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs).json() return self.requests_get('/hardship/%s' % self.fingerprint.upper(), **kwargs).json()
class Newcomers(Blockchain):
"""GET, return block numbers containing newcomers."""
def __get__(self, **kwargs):
return self.requests_get('/with/newcomers', **kwargs).json()
class Certifications(Blockchain):
"""GET, return block numbers containing certifications."""
def __get__(self, **kwargs):
return self.requests_get('/with/certs', **kwargs).json()
class Joiners(Blockchain):
"""GET, return block numbers containing joiners."""
def __get__(self, **kwargs):
return self.requests_get('/with/joiners', **kwargs).json()
class Actives(Blockchain):
"""GET, return block numbers containing actives."""
def __get__(self, **kwargs):
return self.requests_get('/with/actives', **kwargs).json()
class Leavers(Blockchain):
"""GET, return block numbers containing leavers."""
def __get__(self, **kwargs):
return self.requests_get('/with/leavers', **kwargs).json()
class Excluded(Blockchain):
"""GET, return block numbers containing excluded."""
def __get__(self, **kwargs):
return self.requests_get('/with/excluded', **kwargs).json()
class UD(Blockchain):
"""GET, return block numbers containing universal dividend."""
def __get__(self, **kwargs):
return self.requests_get('/with/ud', **kwargs).json()
class TX(Blockchain):
"""GET, return block numbers containing transactions."""
def __get__(self, **kwargs):
return self.requests_get('/with/tx', **kwargs).json()
...@@ -49,3 +49,41 @@ class Lookup(WOT): ...@@ -49,3 +49,41 @@ class Lookup(WOT):
assert self.search is not None assert self.search is not None
return self.requests_get('/lookup/%s' % self.search, **kwargs).json() return self.requests_get('/lookup/%s' % self.search, **kwargs).json()
class CertifiersOf(WOT):
"""GET Certification data over a member."""
def __init__(self, connection_handler, search, module='wot'):
super(WOT, self).__init__(connection_handler, module)
self.search = search
def __get__(self, **kwargs):
assert self.search is not None
return self.requests_get('/certifiers-of/%s' % self.search, **kwargs).json()
class CertifiedBy(WOT):
"""GET Certification data from a member."""
def __init__(self, connection_handler, search, module='wot'):
super(WOT, self).__init__(connection_handler, module)
self.search = search
def __get__(self, **kwargs):
assert self.search is not None
return self.requests_get('/certified-by/%s' % self.search, **kwargs).json()
class Members(WOT):
"""GET List all current members of the Web of Trust."""
def __init__(self, connection_handler, module='wot'):
super(WOT, self).__init__(connection_handler, module)
def __get__(self, **kwargs):
return self.requests_get('/members', **kwargs).json()
...@@ -4,19 +4,12 @@ Created on 3 déc. 2014 ...@@ -4,19 +4,12 @@ Created on 3 déc. 2014
@author: inso @author: inso
''' '''
import base58 import base58
import time import re
from ..key import Base58Encoder from ..key import Base58Encoder
class Document: class Document:
RE_VERSION = re.compile("Version: ([0-9]+)\n")
def __init__(self, version): def __init__(self, version):
self.version = version self.version = version
def content(self):
return ""
def sign(self, key):
return key.sign(self.content(), encoder=Base58Encoder)
def signed(self, key):
return "{0}\n{1}\n".format(self.content(), self.sign(key))
...@@ -6,6 +6,11 @@ Created on 2 déc. 2014 ...@@ -6,6 +6,11 @@ Created on 2 déc. 2014
from .. import PROTOCOL_VERSION from .. import PROTOCOL_VERSION
from . import Document from . import Document
from .certification import SelfCertification, Certification
from .membership import Membership
from .transaction import Transaction
import re
class Block(Document): class Block(Document):
...@@ -48,14 +53,36 @@ COMPACT_TRANSACTION ...@@ -48,14 +53,36 @@ COMPACT_TRANSACTION
BOTTOM_SIGNATURE BOTTOM_SIGNATURE
''' '''
def __init__(self, currency, noonce, number, powmin, time, re_type = re.compile("Type: (Block)\n")
re_noonce = re.compile("Nonce: ([0-9]+)\n")
re_number = re.compile("Number: ([0-9]+)\n")
re_powmin = re.compile("PoWMin: ([0-9]+)\n")
re_time = re.compile("Time: ([0-9]+)\n")
re_mediantime = re.compile("MedianTime: ([0-9]+)\n")
re_universaldividend = re.compile("UniversalDividend: ([0-9]+)\n")
re_issuer = re.compile("Issuer: ([1-9A-Za-z][^OIl]{43,45})\n")
re_previoushash = re.compile("PreviousHash: ([0-9a-fA-F]{5,40})\n")
re_previousissuer = re.compile("PreviousIssuer: ([1-9A-Za-z][^OIl]{43,45})\n")
re_parameters = re.compile("Parameters: ([0-9]+\.[0-9]+)(:[0-9]+){10}\n")
re_memberscount = re.compile("MembersCount: ([0-9]+)\n")
re_identities = re.compile("Identities:\n")
re_joiners = re.compile("Joiners:\n")
re_actives = re.compile("Actives:\n")
re_leavers = re.compile("Leavers:\n")
re_excluded = re.compile("Excluded:\n")
re_certifications = re.compile("Certifications:\n")
re_transactions = re.compile("Transactions:\n")
re_sign = re.compile("([A-Za-z0-9+/]+)")
def __init__(self, version, currency, noonce, number, powmin, time,
mediantime, ud, issuer, prev_hash, prev_issuer, mediantime, ud, issuer, prev_hash, prev_issuer,
parameters, members_count, identities, joiners, parameters, members_count, identities, joiners,
actives, leavers, excluded, certifications, actives, leavers, excluded, certifications,
transactions): transactions, sign):
''' '''
Constructor Constructor
''' '''
super(version)
self.currency = currency self.currency = currency
self.noonce = noonce self.noonce = noonce
self.number = number self.number = number
...@@ -75,6 +102,7 @@ BOTTOM_SIGNATURE ...@@ -75,6 +102,7 @@ BOTTOM_SIGNATURE
self.excluded = excluded self.excluded = excluded
self.certifications = certifications self.certifications = certifications
self.transactions = transactions self.transactions = transactions
self.sign = sign
@classmethod @classmethod
def from_raw(cls, raw): def from_raw(cls, raw):
...@@ -82,62 +110,112 @@ BOTTOM_SIGNATURE ...@@ -82,62 +110,112 @@ BOTTOM_SIGNATURE
lines = raw.splitlines(True) lines = raw.splitlines(True)
n = 0 n = 0
version_re = re.compile("Version: ([0-9]+)\n")
version = version_re.match(lines[n]) version = Block.re_version.match(lines[n]).group(1)
n = 1 n = n + 1
currency_re = re.compile("Currency: ([0-9a-zA-Z_\-]+)\n"
currency = currency_re.match(lines[n]) type = Block.re_type.match(lines[n]).group(1)
n = n + 1
n = 2
noonce_re = re.compile("Nonce: ([0-9]+)\n") currency = Block.re_currency.match(lines[n]).group(1)
noonce = nonce_re.match(lines[n]) n = n + 1
n = 3 noonce = int(Block.re_noonce.match(lines[n])).group(1)
number_re = re.compile("Number: ([0-9]+)\n") n = n + 1
number = number_re.match(lines[n])
number = int(Block.re_number.match(lines[n])).group(1)
n = 4 n = n + 1
powmin_re = re.compile("PoWMin: ([0-9]+)\n")
powmin = powmin.match(lines[n]) powmin = int(Block.re_powmin.match(lines[n])).group(1)
n = n + 1
n = 5
time_re = re.compile("Time: ([0-9]+)\n") time = int(Block.re_time.match(lines[n])).group(1)
time = time.match(lines[n]) n = n + 1
n = 6 mediantime = int(Block.re_mediantime.match(lines[n])).group(1)
mediantime_re = re.compile("MedianTime: ([0-9]+)\n") n = n + 1
mediantime = mediantime_re.match(line[n])
ud = Block.re_universaldividend.match(lines[n]).group(1)
n = 7 if ud is not None:
ud_re = re.compile("UniversalDividend: ([0-9]+)\n") ud = int(ud)
ud = ud_re.match(line[n]) n = n + 1
n = 8 issuer = Block.re_issuer.match(lines[n]).group(1)
issuer_re = re.compile("Issuer: ([1-9A-Za-z][^OIl]{43,45})\n") n = n + 1
issuer = issuer_re.match(line[n])
prev_hash = Block.re_previoushash.match(lines[n]).group(1)
n = 9 n = n + 1()
previoushash_re = re.compile("PreviousHash: ([0-9a-fA-F]{5,40})\n")
prev_hash = previoushash_re.match(line[n]) prev_issuer = Block.re_previousissuer.match(lines[n]).group(1)
n = n + 1
n = 10
previousissuer_re = re.compile("PreviousIssuer: ([1-9A-Za-z][^OIl]{43,45})\n") if number == 0:
prev_issuer = previousissuer_re.match(line[n]) parameters = Block.re_parameters.match(lines[n]).group(1)
n = n + 1
n = 11
parameters = "" members_count = int(Block.re_memberscount.match(lines[n])).group(1)
members_count = "" n = n + 1
identities = ""
joiners = "" identities = []
actives = "" joiners = []
leavers = "" actives = []
excluded = "" leavers = []
certifications = "" excluded = []
transactions = "" certifications = []
transactions = []
return cls([])
if Block.re_identities.match(lines[n]) is not None:
def content(self): while Block.re_joiners.match(lines[n]) is None:
selfcert = SelfCertification.from_inline(version, lines[n])
identities.append(selfcert)
lines = lines + 1
if Block.re_joiners.match(lines[n]) is not None:
while Block.re_actives.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "IN", lines[n])
joiners.append(membership)
lines = lines + 1
if Block.re_actives.match(lines[n]) is not None:
while Block.re_leavers.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "IN", lines[n])
actives.append(membership)
lines = lines + 1
if Block.re_leavers.match(lines[n]) is not None:
while Block.re_excluded.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "OUT", lines[n])
leavers.append(membership)
lines = lines + 1
if Block.re_excluded.match(lines[n]) is not None:
while Block.re_certifications.match(lines[n]) is None:
membership = Membership.from_inline(version, currency, "OUT", lines[n])
excluded.append(membership)
lines = lines + 1
if Block.re_certifications.match(lines[n]) is not None:
while Block.re_transactions.match(lines[n]) is None:
certification = Certification.from_inline(version, lines[n])
certifications.append(certification)
lines = lines + 1
if Block.re_transactions.match(lines[n]) is not None:
while Block.re_transactions.match(lines[n]) is None:
transaction = Transaction.from_compact(version, lines[n])
transactions.append(transaction)
lines = lines + 1
sign = Block.re_sign.match(lines[n])
n = n + 1
return cls(version, currency, noonce, number, powmin, time,
mediantime, ud, issuer, prev_hash, prev_issuer,
parameters, members_count, identities, joiners,
actives, leavers, excluded, certifications,
transactions, sign)
def raw(self):
doc = """ doc = """
Version: {0} Version: {0}
Type: Block Type: Block
...@@ -193,3 +271,5 @@ Identities:""".format(PROTOCOL_VERSION, ...@@ -193,3 +271,5 @@ Identities:""".format(PROTOCOL_VERSION,
doc += "Transactions:\n" doc += "Transactions:\n"
for transaction in self.transactions: for transaction in self.transactions:
doc += "{0}\n".format(transaction.inline()) doc += "{0}\n".format(transaction.inline())
doc += self.sign
...@@ -3,6 +3,8 @@ Created on 2 déc. 2014 ...@@ -3,6 +3,8 @@ Created on 2 déc. 2014
@author: inso @author: inso
''' '''
import re
from . import Document from . import Document
...@@ -11,9 +13,23 @@ class SelfCertification(Document): ...@@ -11,9 +13,23 @@ class SelfCertification(Document):
A document discribing a self certification. A document discribing a self certification.
''' '''
def __init__(self, identifier): re_inline = re.compile("([1-9A-Za-z][^OIl]{43,45}):([A-Za-z0-9+/]+):([0-9]+):([^\n]+)\n")
def __init__(self, version, pubkey, ts, identifier, sign):
super(version)
self.pubkey = pubkey
self.timestamp = ts
self.identifier = identifier self.identifier = identifier
self.timestamp = timestamp self.sign = sign
@classmethod
def from_inline(cls, version, inline):
selfcert_data = SelfCertification.re_inline.match(inline)
pubkey = selfcert_data.group(1)
sign = selfcert_data.group(2)
ts = selfcert_data.group(3)
identifier = selfcert_data.group(4)
return cls(version, pubkey, ts, identifier, sign)
@classmethod @classmethod
def from_raw(cls, raw): def from_raw(cls, raw):
...@@ -26,30 +42,43 @@ class SelfCertification(Document): ...@@ -26,30 +42,43 @@ class SelfCertification(Document):
def uid(self): def uid(self):
return "UID:{0}".format(self.identifier) return "UID:{0}".format(self.identifier)
def content(self): def raw(self):
return "{0}\n{1}".format(self.uid(), self.ts()) return "{0}\n{1}".format(self.uid(), self.ts())
class Certification(Document): class Certification(Document):
''' '''
classdocs A document describing a certification.
''' '''
def __init__(self, selfcert, blockid): re_inline = re.compile("([1-9A-Za-z][^OIl]{43,45}):\
([A-Za-z0-9+/]+)(==)?:([0-9]+):([0-9a-fA-F]{5,40}):\
([0-9]+):([^\n]+)\n")
def __init__(self, version, pubkey_from, pubkey_to,
blockhash, blocknumber, sign):
''' '''
Constructor Constructor
''' '''
self.selfcert = selfcert super(version)
self.blockid = blockid self.pubkey_from = pubkey_from
self.pubkey_to = pubkey_to
self.blockhash = blockhash
self.blocknumber = blocknumber
self.sign = sign
@classmethod @classmethod
def from_raw(cls, raw): def from_inline(cls, version, blockhash, inline):
#TODO : Parsing cert_data = Certification.re_inline.match(inline)
return cls() pubkey_from = cert_data.group(1)
pubkey_to = cert_data.group(2)
blocknumber = cert_data.group(3)
sign = cert_data.group(4)
return cls(version, pubkey_from, pubkey_to,
blockhash, blocknumber, sign)
def ts(self): def ts(self):
return "META:TS:{0}".format(self.blockid) return "META:TS:{0}-{1}".format(self.blockhash, self.blocknumber)
def content(self): def raw(self, selfcert):
return "{0}\n{1}".format(self.selfcert.content(), self.ts()) return "{0}\n{1}".format(selfcert.content(), self.ts())
...@@ -4,9 +4,12 @@ Created on 2 déc. 2014 ...@@ -4,9 +4,12 @@ Created on 2 déc. 2014
@author: inso @author: inso
''' '''
from .. import PROTOCOL_VERSION from .. import PROTOCOL_VERSION
from . import Document
import re
class Membership(object):
class Membership(Document):
''' '''
This is a utility class to generate membership documents : This is a utility class to generate membership documents :
Version: VERSION Version: VERSION
...@@ -19,11 +22,16 @@ class Membership(object): ...@@ -19,11 +22,16 @@ class Membership(object):
CertTS: CERTIFICATION_TS CertTS: CERTIFICATION_TS
''' '''
def __init__(self, currency, issuer, block_number, block_hash, # PUBLIC_KEY:SIGNATURE:NUMBER:HASH:TIMESTAMP:USER_ID
membership_type, userid, cert_ts): re_inline = re.compile("([1-9A-Za-z][^OIl]{43,45}):([A-Za-z0-9+/]+):\
([0-9]+):([0-9a-fA-F]{5,40}):([0-9]+):([^\n]+)\n")
def __init__(self, version, currency, issuer, block_number, block_hash,
membership_type, userid, cert_ts, sign):
''' '''
Constructor Constructor
''' '''
super(version)
self.currency = currency self.currency = currency
self.issuer = issuer self.issuer = issuer
self.block_number = block_number self.block_number = block_number
...@@ -31,15 +39,25 @@ class Membership(object): ...@@ -31,15 +39,25 @@ class Membership(object):
self.membership_type = membership_type self.membership_type = membership_type
self.userid = userid self.userid = userid
self.cert_ts = cert_ts self.cert_ts = cert_ts
self.sign = sign
@classmethod
def from_inline(cls, version, currency, type, inline):
data = Membership.re_inline.match(inline)
issuer = data.group(1)
sign = data.group(2)
block_number = data.group(3)
block_hash = data.group(4)
cert_ts = data.group(5)
userid = data.group(6)
return cls(version, currency, issuer, block_number,
block_hash, type, userid, cert_ts, sign)
@classmethod @classmethod
def from_raw(cls, raw): def from_raw(cls, raw):
#TODO : Parsing #TODO : Parsing
return cls() return cls()
def content(self): def content(self):
return """ return """
Version: {0} Version: {0}
...@@ -59,7 +77,7 @@ CertTS: {7}""".format(PROTOCOL_VERSION, ...@@ -59,7 +77,7 @@ CertTS: {7}""".format(PROTOCOL_VERSION,
def inline(self): def inline(self):
return "{0}:{1}:{2}:{3}".format(self.issuer, return "{0}:{1}:{2}:{3}".format(self.issuer,
self.sign(), self.sign,
self.block_number, self.block_number,
self.block_hash, self.block_hash,
self.cert_ts) self.cert_ts)
...@@ -59,22 +59,22 @@ class Endpoint(): ...@@ -59,22 +59,22 @@ class Endpoint():
def from_inline(inline): def from_inline(inline):
for api in MANAGED_API: for api in MANAGED_API:
if (inline.startswith(api)): if (inline.startswith(api)):
return Endpoint.parse_line(inline, api)
@staticmethod
def parse_line(self, inline, api):
if (api == "BASIC_MERKLED_API"): if (api == "BASIC_MERKLED_API"):
bma_endpoints = re.compile('^BASIC_MERKLED_API( ([a-z_][a-z0-9-_.]+))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$') return BMAEndpoint.from_inline(inline)
m = bma_endpoints.match(inline)
class BMAEndpoint(Endpoint):
re_inline = re.compile('^BASIC_MERKLED_API( ([a-z_][a-z0-9-_.]+))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$')
@classmethod
def from_inline(cls, inline):
m = BMAEndpoint.re_inline.match(inline)
server = m.group(2) server = m.group(2)
ipv4 = m.group(4) ipv4 = m.group(4)
ipv6 = m.group(6) ipv6 = m.group(6)
port = int(m.group(8)) port = int(m.group(8))
return BMAEndpoint(server, ipv4, ipv6, port) return cls(server, ipv4, ipv6, port)
return None
class BMAEndpoint(Endpoint):
def __init__(self, server, ipv4, ipv6, port): def __init__(self, server, ipv4, ipv6, port):
self.server = server self.server = server
self.ipv4 = ipv4 self.ipv4 = ipv4
......
...@@ -37,6 +37,10 @@ SIGNATURES ...@@ -37,6 +37,10 @@ SIGNATURES
self.outputs = outputs self.outputs = outputs
self.comment = comment self.comment = comment
@classmethod
def from_compact(cls, compact):
return None
@classmethod @classmethod
def from_raw(cls, raw): def from_raw(cls, raw):
#TODO : Parsing #TODO : Parsing
......
...@@ -5,6 +5,25 @@ Ucoin public and private keys ...@@ -5,6 +5,25 @@ Ucoin public and private keys
''' '''
import base58 import base58
import base64
import scrypt
from nacl.signing import SigningKey as NaclSigningKey
SEED_LENGTH = 32 # Length of the key
crypto_sign_BYTES = 64
SCRYPT_PARAMS = {'N': 4096,
'r': 16,
'p': 1
}
class SigningKey(NaclSigningKey):
def __init__(self, password, salt):
seed = scrypt.hash(password, salt,
SCRYPT_PARAMS['N'], SCRYPT_PARAMS['r'], SCRYPT_PARAMS['p'],
SEED_LENGTH)
seedb64 = base64.b64encode(seed)
class Base58Encoder(object): class Base58Encoder(object):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment