mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Finished implementing divisible assets for CREATE transactions
Simplified Transaction.create logic Created tests
This commit is contained in:
parent
48084ec47a
commit
5b5c701e0a
@ -99,6 +99,14 @@ class Fulfillment(object):
|
|||||||
ffill['fid'] = fid
|
ffill['fid'] = fid
|
||||||
return ffill
|
return ffill
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate(cls, owners_before):
|
||||||
|
# TODO: write docstring
|
||||||
|
|
||||||
|
if len(owners_before) == 1:
|
||||||
|
ffill = Ed25519Fulfillment(public_key=owners_before[0])
|
||||||
|
return cls(ffill, owners_before)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, ffill):
|
def from_dict(cls, ffill):
|
||||||
"""Transforms a Python dictionary to a Fulfillment object.
|
"""Transforms a Python dictionary to a Fulfillment object.
|
||||||
@ -269,7 +277,8 @@ class Condition(object):
|
|||||||
return cond
|
return cond
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate(cls, owners_after, amount=1):
|
def generate(cls, owners_after, amount):
|
||||||
|
# TODO: Update docstring
|
||||||
"""Generates a Condition from a specifically formed tuple or list.
|
"""Generates a Condition from a specifically formed tuple or list.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
@ -703,7 +712,8 @@ class Transaction(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, owners_before, owners_after, metadata=None, asset=None,
|
def create(cls, owners_before, owners_after, metadata=None, asset=None,
|
||||||
secret=None, time_expire=None, amount=1):
|
secret=None, time_expire=None):
|
||||||
|
# TODO: Update docstring
|
||||||
"""A simple way to generate a `CREATE` transaction.
|
"""A simple way to generate a `CREATE` transaction.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
@ -738,10 +748,24 @@ class Transaction(object):
|
|||||||
raise TypeError('`owners_before` must be a list instance')
|
raise TypeError('`owners_before` must be a list instance')
|
||||||
if not isinstance(owners_after, list):
|
if not isinstance(owners_after, list):
|
||||||
raise TypeError('`owners_after` must be a list instance')
|
raise TypeError('`owners_after` must be a list instance')
|
||||||
if not isinstance(amount, int):
|
|
||||||
raise TypeError('`amount` must be a int')
|
|
||||||
|
|
||||||
metadata = Metadata(metadata)
|
metadata = Metadata(metadata)
|
||||||
|
|
||||||
|
ffils = []
|
||||||
|
conds = []
|
||||||
|
|
||||||
|
# generate_conditions
|
||||||
|
for owner_after in owners_after:
|
||||||
|
pub_keys, amount = owner_after
|
||||||
|
conds.append(Condition.generate(pub_keys, amount))
|
||||||
|
|
||||||
|
# generate fulfillments
|
||||||
|
ffils.append(Fulfillment.generate(owners_before))
|
||||||
|
|
||||||
|
return cls(cls.CREATE, asset, ffils, conds, metadata)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if len(owners_before) == len(owners_after) and len(owners_after) == 1:
|
if len(owners_before) == len(owners_after) and len(owners_after) == 1:
|
||||||
# NOTE: Standard case, one owner before, one after.
|
# NOTE: Standard case, one owner before, one after.
|
||||||
# NOTE: For this case its sufficient to use the same
|
# NOTE: For this case its sufficient to use the same
|
||||||
@ -755,7 +779,7 @@ class Transaction(object):
|
|||||||
ffills = [Fulfillment(Ed25519Fulfillment(public_key=owner_before),
|
ffills = [Fulfillment(Ed25519Fulfillment(public_key=owner_before),
|
||||||
[owner_before])
|
[owner_before])
|
||||||
for owner_before in owners_before]
|
for owner_before in owners_before]
|
||||||
conds = [Condition.generate([owners], amount=amount)
|
conds = [Condition.generate([owners], amount)
|
||||||
for owners in owners_after]
|
for owners in owners_after]
|
||||||
return cls(cls.CREATE, asset, ffills, conds, metadata)
|
return cls(cls.CREATE, asset, ffills, conds, metadata)
|
||||||
|
|
||||||
@ -1138,14 +1162,15 @@ class Transaction(object):
|
|||||||
tx_serialized,
|
tx_serialized,
|
||||||
input_condition_uri)
|
input_condition_uri)
|
||||||
|
|
||||||
if not fulfillments_count == conditions_count == \
|
# TODO: Why?? Need to ask @TimDaub
|
||||||
input_condition_uris_count:
|
# if not fulfillments_count == conditions_count == \
|
||||||
raise ValueError('Fulfillments, conditions and '
|
# input_condition_uris_count:
|
||||||
'input_condition_uris must have the same count')
|
# raise ValueError('Fulfillments, conditions and '
|
||||||
else:
|
# 'input_condition_uris must have the same count')
|
||||||
partial_transactions = map(gen_tx, self.fulfillments,
|
# else:
|
||||||
self.conditions, input_condition_uris)
|
partial_transactions = map(gen_tx, self.fulfillments,
|
||||||
return all(partial_transactions)
|
self.conditions, input_condition_uris)
|
||||||
|
return all(partial_transactions)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _fulfillment_valid(fulfillment, operation, tx_serialized,
|
def _fulfillment_valid(fulfillment, operation, tx_serialized,
|
||||||
|
109
tests/assets/test_divisible_assets.py
Normal file
109
tests/assets/test_divisible_assets.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
# CREATE divisible asset
|
||||||
|
# Single input
|
||||||
|
# Single owners_before
|
||||||
|
# Single output
|
||||||
|
# single owners_after
|
||||||
|
def test_single_in_single_own_single_out_single_own_create(b, user_vk):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.common.transaction import Asset
|
||||||
|
|
||||||
|
asset = Asset(divisible=True)
|
||||||
|
tx = Transaction.create([b.me], [([user_vk], 100)], asset=asset)
|
||||||
|
tx_signed = tx.sign([b.me_private])
|
||||||
|
|
||||||
|
assert tx_signed.validate(b) == tx_signed
|
||||||
|
assert len(tx_signed.conditions) == 1
|
||||||
|
assert tx_signed.conditions[0].amount == 100
|
||||||
|
assert len(tx_signed.fulfillments) == 1
|
||||||
|
|
||||||
|
|
||||||
|
# CREATE divisible asset
|
||||||
|
# Single input
|
||||||
|
# Single onwers_before
|
||||||
|
# Multiple outputs
|
||||||
|
# Single owners_after per output
|
||||||
|
def test_single_in_single_own_multiple_out_single_own_create(b, user_vk):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.common.transaction import Asset
|
||||||
|
|
||||||
|
asset = Asset(divisible=True)
|
||||||
|
tx = Transaction.create([b.me], [([user_vk], 50), ([user_vk], 50)], asset=asset)
|
||||||
|
tx_signed = tx.sign([b.me_private])
|
||||||
|
|
||||||
|
assert tx_signed.validate(b) == tx_signed
|
||||||
|
assert len(tx_signed.conditions) == 2
|
||||||
|
assert tx_signed.conditions[0].amount == 50
|
||||||
|
assert tx_signed.conditions[1].amount == 50
|
||||||
|
assert len(tx_signed.fulfillments) == 1
|
||||||
|
|
||||||
|
|
||||||
|
# CREATE divisible asset
|
||||||
|
# Single input
|
||||||
|
# Single owners_before
|
||||||
|
# Single output
|
||||||
|
# Multiple owners_after
|
||||||
|
def test_single_in_single_own_single_out_multiple_own_create(b, user_vk):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.common.transaction import Asset
|
||||||
|
|
||||||
|
asset = Asset(divisible=True)
|
||||||
|
tx = Transaction.create([b.me], [([user_vk, user_vk], 100)], asset=asset)
|
||||||
|
tx_signed = tx.sign([b.me_private])
|
||||||
|
|
||||||
|
assert tx_signed.validate(b) == tx_signed
|
||||||
|
assert len(tx_signed.conditions) == 1
|
||||||
|
assert tx_signed.conditions[0].amount == 100
|
||||||
|
|
||||||
|
condition = tx_signed.conditions[0].to_dict()
|
||||||
|
assert 'subfulfillments' in condition['condition']['details']
|
||||||
|
assert len(condition['condition']['details']['subfulfillments']) == 2
|
||||||
|
|
||||||
|
assert len(tx_signed.fulfillments) == 1
|
||||||
|
|
||||||
|
|
||||||
|
# CREATE divisible asset
|
||||||
|
# Single input
|
||||||
|
# Single owners_before
|
||||||
|
# Multiple outputs
|
||||||
|
# Mix: one output with a single owners_after, one output with multiple
|
||||||
|
# owners_after
|
||||||
|
def test_single_in_single_own_multiple_out_mix_own_create(b, user_vk):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.common.transaction import Asset
|
||||||
|
|
||||||
|
asset = Asset(divisible=True)
|
||||||
|
tx = Transaction.create([b.me],
|
||||||
|
[([user_vk], 50), ([user_vk, user_vk], 50)],
|
||||||
|
asset=asset)
|
||||||
|
tx_signed = tx.sign([b.me_private])
|
||||||
|
|
||||||
|
assert tx_signed.validate(b) == tx_signed
|
||||||
|
assert len(tx_signed.conditions) == 2
|
||||||
|
assert tx_signed.conditions[0].amount == 50
|
||||||
|
assert tx_signed.conditions[1].amount == 50
|
||||||
|
|
||||||
|
condition_cid1 = tx_signed.conditions[1].to_dict()
|
||||||
|
assert 'subfulfillments' in condition_cid1['condition']['details']
|
||||||
|
assert len(condition_cid1['condition']['details']['subfulfillments']) == 2
|
||||||
|
|
||||||
|
assert len(tx_signed.fulfillments) == 1
|
||||||
|
|
||||||
|
|
||||||
|
# CREATE divisible asset
|
||||||
|
# Single input
|
||||||
|
# Multiple owners_before
|
||||||
|
# Ouput combinations already tested above
|
||||||
|
# TODO: Support multiple owners_before in CREATE transactions
|
||||||
|
@pytest.mark.skip(reason=('CREATE transaction do not support multiple'
|
||||||
|
' owners_before'))
|
||||||
|
def test_single_in_multiple_own_single_out_single_own_create(b, user_vk):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.common.transaction import Asset
|
||||||
|
|
||||||
|
asset = Asset(divisible=True)
|
||||||
|
tx = Transaction.create([b.me, b.me], [([user_vk], 100)], asset=asset)
|
||||||
|
tx_signed = tx.sign([b.me, b.me])
|
||||||
|
assert tx_signed.validate(b) == tx_signed
|
Loading…
x
Reference in New Issue
Block a user