Compliance to legacy BDB models

This commit is contained in:
tim 2016-08-23 20:08:51 +02:00 committed by Sylvain Bellemare
parent 45a946fc24
commit b2b0f56e40
2 changed files with 54 additions and 22 deletions

View File

@ -2,6 +2,10 @@
""" """
class ConfigurationError(Exception):
"""Raised when there is a problem with server configuration"""
class OperationError(Exception): class OperationError(Exception):
"""Raised when an operation cannot go through""" """Raised when an operation cannot go through"""

View File

@ -103,24 +103,30 @@ class TransactionLink(object):
# NOTE: In an IPLD implementation, this class is not necessary anymore, as an IPLD link can simply point to an # NOTE: In an IPLD implementation, this class is not necessary anymore, as an IPLD link can simply point to an
# object, as well as an objects properties. So instead of having a (de)serializable class, we can have a # object, as well as an objects properties. So instead of having a (de)serializable class, we can have a
# simple IPLD link of the form: `/<tx_id>/transaction/conditions/<cid>/` # simple IPLD link of the form: `/<tx_id>/transaction/conditions/<cid>/`
def __init__(self, transaction_id=None, condition_id=None): def __init__(self, txid=None, cid=None):
self.transaction_id = transaction_id self.txid = txid
self.condition_id = condition_id self.cid = cid
def is_defined(self):
if self.txid is None and self.cid is None:
return False
else:
return True
@classmethod @classmethod
def from_dict(cls, link): def from_dict(cls, link):
try: try:
return cls(link['transaction_id'], link['condition_id']) return cls(link['txid'], link['cid'])
except TypeError: except TypeError:
return cls() return cls()
def to_dict(self): def to_dict(self):
if self.transaction_id is None and self.condition_id is None: if self.txid is None and self.cid is None:
return None return None
else: else:
return { return {
'transaction_id': self.transaction_id, 'txid': self.txid,
'condition_id': self.condition_id, 'cid': self.cid,
} }
@ -166,7 +172,7 @@ class Data(object):
@classmethod @classmethod
def from_dict(cls, payload): def from_dict(cls, payload):
try: try:
return cls(payload['payload'], payload['hash']) return cls(payload['payload'], payload['uuid'])
except TypeError: except TypeError:
return cls() return cls()
@ -176,16 +182,18 @@ class Data(object):
else: else:
return { return {
'payload': self.payload, 'payload': self.payload,
'hash': str(self.payload_id), 'uuid': self.payload_id,
} }
def to_hash(self): def to_hash(self):
return uuid4() return str(uuid4())
class Transaction(object): class Transaction(object):
CREATE = 'CREATE' CREATE = 'CREATE'
TRANSFER = 'TRANSFER' TRANSFER = 'TRANSFER'
GENESIS = 'GENESIS'
ALLOWED_OPERATIONS = (CREATE, TRANSFER, GENESIS)
VERSION = 1 VERSION = 1
def __init__(self, operation, fulfillments=None, conditions=None, data=None, timestamp=None, version=None): def __init__(self, operation, fulfillments=None, conditions=None, data=None, timestamp=None, version=None):
@ -233,7 +241,7 @@ class Transaction(object):
self.timestamp = timestamp if timestamp is not None else gen_timestamp() self.timestamp = timestamp if timestamp is not None else gen_timestamp()
self.version = version if version is not None else Transaction.VERSION self.version = version if version is not None else Transaction.VERSION
if operation is not Transaction.CREATE and operation is not Transaction.TRANSFER: if operation not in Transaction.ALLOWED_OPERATIONS:
raise TypeError('`operation` must be either CREATE or TRANSFER') raise TypeError('`operation` must be either CREATE or TRANSFER')
else: else:
self.operation = operation self.operation = operation
@ -257,6 +265,31 @@ class Transaction(object):
else: else:
self.data = data self.data = data
@classmethod
def create(cls, owners_before, owners_after, inputs, operation, payload=None):
if operation == Transaction.CREATE or operation == Transaction.GENESIS:
ffill = Fulfillment.gen_default(owners_after)
cond = ffill.gen_condition()
return cls(operation, [ffill], [cond], Data(payload))
else:
# TODO: Replace this with an actual implementation, maybe calling
# `self.transfer` is sufficient already :)
raise NotImplementedError()
def transfer(self, conditions):
# TODO: Check here if a condition is submitted or smth else
return Transaction(Transaction.TRANSFER, self._fulfillments_as_inputs(), conditions)
def simple_transfer(self, owners_after):
condition = Fulfillment.gen_default(owners_after).gen_condition()
return self.transfer([condition])
def _fulfillments_as_inputs(self):
return [Fulfillment(ffill.fulfillment,
ffill.owners_before,
TransactionLink(self.to_hash(), fulfillment_id))
for fulfillment_id, ffill in enumerate(self.fulfillments)]
def add_fulfillment(self, fulfillment): def add_fulfillment(self, fulfillment):
if fulfillment is not None and not isinstance(fulfillment, Fulfillment): if fulfillment is not None and not isinstance(fulfillment, Fulfillment):
raise TypeError('`fulfillment` must be a Fulfillment instance or None') raise TypeError('`fulfillment` must be a Fulfillment instance or None')
@ -396,7 +429,7 @@ class Transaction(object):
else: else:
return tx.fulfillments_valid() return tx.fulfillments_valid()
if self.operation is Transaction.CREATE: if self.operation in (Transaction.CREATE, Transaction.GENESIS):
if not fulfillments_count == conditions_count: if not fulfillments_count == conditions_count:
raise ValueError('Fulfillments, conditions must have the same count') raise ValueError('Fulfillments, conditions must have the same count')
elif fulfillments_count > 1 and conditions_count > 1: elif fulfillments_count > 1 and conditions_count > 1:
@ -411,7 +444,7 @@ class Transaction(object):
else: else:
return self._fulfillment_valid(input_condition_uris.pop()) return self._fulfillment_valid(input_condition_uris.pop())
else: else:
raise TypeError('`operation` must be either `Transaction.TRANSFER` or `Transaction.CREATE`') raise TypeError('`operation` must be either `TRANSFER`, `CREATE` or `GENESIS`')
def _fulfillment_valid(self, input_condition_uri=None): def _fulfillment_valid(self, input_condition_uri=None):
# NOTE: We're always taking the first fulfillment, as this method is called recursively. # NOTE: We're always taking the first fulfillment, as this method is called recursively.
@ -435,15 +468,6 @@ class Transaction(object):
# it. # it.
return parsed_fulfillment.validate(message=tx_serialized, now=gen_timestamp()) and input_condition_valid return parsed_fulfillment.validate(message=tx_serialized, now=gen_timestamp()) and input_condition_valid
def transfer(self, conditions):
return Transaction(Transaction.TRANSFER, self._fulfillments_as_inputs(), conditions)
def _fulfillments_as_inputs(self):
return [Fulfillment(ffill.fulfillment,
ffill.owners_before,
TransactionLink(self.to_hash(), fulfillment_id))
for fulfillment_id, ffill in enumerate(self.fulfillments)]
def to_dict(self): def to_dict(self):
try: try:
data = self.data.to_dict() data = self.data.to_dict()
@ -490,6 +514,10 @@ class Transaction(object):
def _to_hash(value): def _to_hash(value):
return hash_data(value) return hash_data(value)
@property
def id(self):
return self.to_hash()
def to_hash(self): def to_hash(self):
return self.to_dict()['id'] return self.to_dict()['id']