Skip to content
Snippets Groups Projects
Commit 1eb1f982 authored by Caner Candan's avatar Caner Candan
Browse files

Merge branch 'master' of github.com:canercandan/ucoin-python-api

parents 3d3893de b47db736
No related branches found
No related tags found
No related merge requests found
...@@ -177,9 +177,9 @@ class API: ...@@ -177,9 +177,9 @@ class API:
return response return response
def merkle_easy_parser(self, path): def merkle_easy_parser(self, path, begin=None, end=None):
root = self.requests_get(path, leaves='true').json() root = self.requests_get(path, leaves='true').json()
for leaf in root['leaves']: for leaf in root['leaves'][begin:end]:
yield self.requests_get(path, leaf=leaf).json()['leaf'] yield self.requests_get(path, leaf=leaf).json()['leaf']
from . import pks, ucg, hdc, wrappers from . import pks, ucg, hdc, wrappers
...@@ -71,34 +71,42 @@ class Last(Base): ...@@ -71,34 +71,42 @@ class Last(Base):
class Sender(Base): class Sender(Base):
"""GET all the transactions sent by this sender and stored by this node (should contain all transactions of the sender).""" """GET all the transactions sent by this sender and stored by this node (should contain all transactions of the sender)."""
def __init__(self, pgp_fingerprint): def __init__(self, pgp_fingerprint, begin=None, end=None):
""" """
Arguments: Arguments:
- `pgp_fingerprint`: PGP fingerprint of the key we want to see sent transactions. - `pgp_fingerprint`: PGP fingerprint of the key we want to see sent transactions.
- `begin`: integer value used by the merkle parser to know when to begin requesting.
- `end`: integer value used by the merkle parser to know when to end requesting.
""" """
super().__init__() super().__init__()
self.pgp_fingerprint = pgp_fingerprint self.pgp_fingerprint = pgp_fingerprint
self.begin = begin
self.end = end
def __get__(self, **kwargs): def __get__(self, **kwargs):
return self.merkle_easy_parser('/sender/%s' % self.pgp_fingerprint) return self.merkle_easy_parser('/sender/%s' % self.pgp_fingerprint, begin=self.begin, end=self.end)
class Recipient(Base): class Recipient(Base):
"""GET all the transactions received for this recipient stored by this node.""" """GET all the transactions received for this recipient stored by this node."""
def __init__(self, pgp_fingerprint): def __init__(self, pgp_fingerprint, begin=None, end=None):
""" """
Arguments: Arguments:
- `pgp_fingerprint`: PGP fingerprint of the key we want to see sent transactions. - `pgp_fingerprint`: PGP fingerprint of the key we want to see sent transactions.
- `begin`: integer value used by the merkle parser to know when to begin requesting.
- `end`: integer value used by the merkle parser to know when to end requesting.
""" """
super().__init__() super().__init__()
self.pgp_fingerprint = pgp_fingerprint self.pgp_fingerprint = pgp_fingerprint
self.begin = begin
self.end = end
def __get__(self, **kwargs): def __get__(self, **kwargs):
return self.merkle_easy_parser('/recipient/%s' % self.pgp_fingerprint) return self.merkle_easy_parser('/recipient/%s' % self.pgp_fingerprint, begin=self.begin, end=self.end)
class View(Base): class View(Base):
"""GET the transaction of given TRANSACTION_ID.""" """GET the transaction of given TRANSACTION_ID."""
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
# Caner Candan <caner@candan.fr>, http://caner.candan.fr # Caner Candan <caner@candan.fr>, http://caner.candan.fr
# #
import hashlib, logging import logging
from .. import pks, ucg, hdc, settings from .. import pks, ucg, hdc, settings
logger = logging.getLogger("wrappers") logger = logging.getLogger("wrappers")
...@@ -26,170 +26,4 @@ class Wrapper: ...@@ -26,170 +26,4 @@ class Wrapper:
def __call__(self): def __call__(self):
pass pass
class Transaction(Wrapper): from . import transactions, coins
def __init__(self, type, pgp_fingerprint, message=''):
self.pgp_fingerprint = pgp_fingerprint
self.message = message
self.type = type
def __call__(self):
try:
last_tx = hdc.transactions.sender.Last(self.pgp_fingerprint).get()
except ValueError:
last_tx = None
context_data = {}
context_data.update(settings)
context_data['version'] = 1
context_data['number'] = 0 if not last_tx else last_tx['transaction']['number']+1
context_data['previousHash'] = hashlib.sha1(("%(raw)s%(signature)s" % last_tx).encode('ascii')).hexdigest().upper() if last_tx else None
context_data['message'] = self.message
context_data['type'] = self.type
context_data.update(self.get_context_data())
tx = """\
Version: %(version)d
Currency: %(currency)s
Sender: %(fingerprint)s
Number: %(number)d
""" % context_data
if last_tx: tx += "PreviousHash: %(previousHash)s\n" % context_data
tx += self.get_message(context_data)
tx += """\
Comment:
%(message)s
""" % context_data
tx = tx.replace("\n", "\r\n")
txs = settings['gpg'].sign(tx, detach=True)
return self.process(tx, txs)
def get_context_data(self):
return {}
def get_message(self, context_data, tx=''):
return tx
def process(self, tx, txs):
try:
hdc.transactions.Process().post(transaction=tx, signature=txs)
except ValueError as e:
print(e)
else:
return True
return False
class Transfer(Transaction):
def __init__(self, pgp_fingerprint, recipient, coins, message=''):
super().__init__('TRANSFER', pgp_fingerprint, message)
self.recipient = recipient
self.coins = coins
def get_message(self, context_data, tx=''):
context_data['recipient'] = self.recipient
tx += """\
Recipient: %(recipient)s
Type: %(type)s
Coins:
""" % context_data
for coin in self.coins.split(','):
data = coin.split(':')
issuer = data[0]
for number in data[1:]:
context_data.update(hdc.coins.View(issuer, int(number)).get())
tx += '%(id)s, %(transaction)s\n' % context_data
return tx
class Issue(Transaction):
def __init__(self, pgp_fingerprint, amendment, coins, message=''):
super().__init__('ISSUANCE', pgp_fingerprint, message)
self.amendment = amendment
self.coins = coins
def get_next_coin_number(self, coins):
number = 0
for c in coins:
candidate = int(c['id'].split('-')[1])
if candidate > number: number = candidate
return number+1
def get_message(self, context_data, tx=''):
context_data['amendment'] = self.amendment
tx += """\
Recipient: %(fingerprint)s
Type: %(type)s
Coins:
""" % context_data
try:
last_issuance = hdc.transactions.sender.issuance.Last(self.pgp_fingerprint).get()
except ValueError:
last_issuance = None
previous_idx = 0 if not last_issuance else self.get_next_coin_number(last_issuance['transaction']['coins'])
for idx, coin in enumerate(self.coins):
context_data['idx'] = idx+previous_idx
context_data['base'], context_data['power'] = [int(x) for x in coin.split(',')]
tx += '%(fingerprint)s-%(idx)d-%(base)d-%(power)d-A-%(amendment)d\n' % context_data
return tx
class CoinsWrapper(Wrapper):
def __init__(self, pgp_fingerprint):
self.pgp_fingerprint = pgp_fingerprint
class CoinsGet(CoinsWrapper):
def __init__(self, pgp_fingerprint, values):
super().__init__(pgp_fingerprint)
self.values = values
def __call__(self):
__list = hdc.coins.List(self.pgp_fingerprint).get()
coins = {}
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
coins[amount] = {'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount}
issuers = {}
for v in self.values:
if v in coins:
c = coins[v]
issuers[c['issuer']] = issuers.get(c['issuer']) or []
issuers[c['issuer']].append(c)
else:
raise ValueError('You do not have enough coins of value (%d)' % v)
res = ''
for i, issuer in enumerate(issuers):
if i > 0: res += ','
res += issuer
for c in issuers[issuer]:
res += ':%(number)d' % c
return res
class CoinsList(CoinsWrapper):
def __call__(self):
__list = hdc.coins.List(self.pgp_fingerprint).get()
coins = []
__sum = 0
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
__dict = {'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount}
coins.append(__dict)
__sum += amount
return __sum, coins
#!/usr/bin/env python3
#
# 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
#
import logging
from . import Wrapper, pks, ucg, hdc, settings
logger = logging.getLogger("coins")
class Coins(Wrapper):
def __init__(self, pgp_fingerprint):
self.pgp_fingerprint = pgp_fingerprint
class Get(Coins):
def __init__(self, pgp_fingerprint, values):
super().__init__(pgp_fingerprint)
self.values = values
def __call__(self):
__list = hdc.coins.List(self.pgp_fingerprint).get()
coins = {}
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
if amount not in coins: coins[amount] = []
coins[amount].append({'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount})
issuers = {}
for v in self.values:
if v in coins and coins[v]:
c = coins[v].pop()
issuers[c['issuer']] = issuers.get(c['issuer']) or []
issuers[c['issuer']].append(c)
else:
raise ValueError('You do not have enough coins of value (%d)' % v)
res = ''
for i, issuer in enumerate(issuers):
if i > 0: res += ','
res += issuer
for c in issuers[issuer]:
res += ':%(number)d' % c
return res
class List(Coins):
def __init__(self, pgp_fingerprint, limit=None):
super().__init__(pgp_fingerprint)
self.limit = limit
def __call__(self):
__list = hdc.coins.List(self.pgp_fingerprint).get()
coins = []
__sum = 0
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
__dict = {'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount}
if not self.limit or self.limit >= amount:
coins.append(__dict)
__sum += amount
return __sum, coins
#!/usr/bin/env python3
#
# 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
#
import hashlib, logging
from . import Wrapper, pks, ucg, hdc, settings
logger = logging.getLogger("transactions")
class Transaction(Wrapper):
def __init__(self, type, pgp_fingerprint, message='', peering=None):
self.pgp_fingerprint = pgp_fingerprint
self.message = message
self.type = type
self.error = None
self.peering = peering
def __call__(self):
try:
last_tx = hdc.transactions.sender.Last(self.pgp_fingerprint).get()
except ValueError:
last_tx = None
context_data = {}
context_data.update(settings)
context_data.update(self.peering if self.peering else ucg.Peering().get())
context_data['version'] = 1
context_data['number'] = 0 if not last_tx else last_tx['transaction']['number']+1
context_data['previousHash'] = hashlib.sha1(("%(raw)s%(signature)s" % last_tx).encode('ascii')).hexdigest().upper() if last_tx else None
context_data['message'] = self.message
context_data['type'] = self.type
context_data['fingerprint'] = self.pgp_fingerprint
context_data.update(self.get_context_data())
tx = """\
Version: %(version)d
Currency: %(currency)s
Sender: %(fingerprint)s
Number: %(number)d
""" % context_data
if last_tx: tx += "PreviousHash: %(previousHash)s\n" % context_data
try:
tx += self.get_message(context_data)
except ValueError as e:
self.error = e
return False
tx += """\
Comment:
%(message)s
""" % context_data
tx = tx.replace("\n", "\r\n")
txs = settings['gpg'].sign(tx, detach=True)
return self.process(tx, txs)
def get_context_data(self):
return {}
def get_message(self, context_data, tx=''):
return tx
def get_error(self):
return self.error
def process(self, tx, txs):
try:
hdc.transactions.Process().post(transaction=tx, signature=txs)
except ValueError as e:
self.error = str(e)
else:
return True
return False
def parse_coins(self, coins_message):
coins = []
for coin in coins_message.split(','):
data = coin.split(':')
issuer, numbers = data[0], data[1:]
for number in numbers:
view = hdc.coins.View(issuer, int(number)).get()
if view['owner'] != self.pgp_fingerprint:
raise ValueError('Trying to divide a coin you do not own (%s)' % view['id'])
coins.append(view)
return coins
def get_coins_sum(self, coins):
__sum = 0
for coin in coins:
base, power = coin['id'].split('-')[2:4]
__sum += int(base) * 10**int(power)
return __sum
def check_coins_sum(self, __sum):
m = re.match(r'^(\d)(0*)$', str(__sum))
if not m: raise ValueError('bad sum value %d' % __sum)
class Transfer(Transaction):
def __init__(self, pgp_fingerprint, recipient, coins, message=''):
super().__init__('TRANSFER', pgp_fingerprint, message)
self.recipient = recipient
self.coins = coins
def get_message(self, context_data, tx=''):
context_data['recipient'] = self.recipient
tx += """\
Recipient: %(recipient)s
Type: %(type)s
Coins:
""" % context_data
for coin in self.coins.split(','):
data = coin.split(':')
issuer = data[0]
for number in data[1:]:
context_data.update(hdc.coins.View(issuer, int(number)).get())
tx += '%(id)s, %(transaction)s\n' % context_data
return tx
class MonoTransaction(Transaction):
def get_next_coin_number(self, coins):
number = 0
for c in coins:
candidate = int(c['id'].split('-')[1])
if candidate > number: number = candidate
return number+1
def get_message(self, context_data, tx=''):
tx += """\
Recipient: %(fingerprint)s
Type: %(type)s
Coins:
""" % context_data
try:
last_issuance = hdc.transactions.sender.issuance.Last(self.pgp_fingerprint).get()
except ValueError:
last_issuance = None
context_data['previous_idx'] = 0 if not last_issuance else self.get_next_coin_number(last_issuance['transaction']['coins'])
tx += self.get_mono_message(context_data)
return tx
def get_mono_message(self, context_data, tx=''):
return tx
class Issue(MonoTransaction):
def __init__(self, pgp_fingerprint, amendment, coins, message=''):
super().__init__('ISSUANCE', pgp_fingerprint, message)
self.amendment = amendment
self.coins = coins
def get_mono_message(self, context_data, tx=''):
context_data['amendment'] = self.amendment
for idx, coin in enumerate(self.coins):
context_data['idx'] = idx + context_data['previous_idx']
context_data['base'], context_data['power'] = [int(x) for x in coin.split(',')]
tx += '%(fingerprint)s-%(idx)d-%(base)d-%(power)d-A-%(amendment)d\n' % context_data
return tx
class Fusion(MonoTransaction):
def __init__(self, pgp_fingerprint, coins, message=''):
super().__init__('FUSION', pgp_fingerprint, message)
self.coins = coins
def get_mono_message(self, context_data, tx=''):
coins = self.parse_coins(self.coins)
self.check_coins_sum(self.get_coins_sum(coins))
context_data['base'], context_data['power'] = int(m.groups()[0]), len(m.groups()[1])
tx += '%(fingerprint)s-%(previous_idx)d-%(base)d-%(power)d-F-%(number)d\n' % context_data
for coin in coins: tx += '%(id)s, %(transaction)s\n' % coin
return tx
class Divide(MonoTransaction):
def __init__(self, pgp_fingerprint, old_coins, new_coins, message=''):
super().__init__('DIVISION', pgp_fingerprint, message)
self.old_coins = old_coins
self.new_coins = new_coins
def get_mono_message(self, context_data, tx=''):
old_coins = self.parse_coins(self.old_coins)
old_coins_sum = self.get_coins_sum(old_coins)
new_coins_sum = 0
for idx, coin in enumerate(self.new_coins):
context_data['idx'] = idx + context_data['previous_idx']
context_data['base'], context_data['power'] = [int(x) for x in coin.split(',')]
new_coins_sum += context_data['base'] * 10**context_data['power']
tx += '%(fingerprint)s-%(idx)d-%(base)d-%(power)d-D-%(number)d\n' % context_data
if old_coins_sum != new_coins_sum:
raise ValueError('Amount of old coins (%d) is not equal to new coins (%d)' % (old_coins_sum, new_coins_sum))
for coin in old_coins: tx += '%(id)s, %(transaction)s\n' % coin
return tx
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment