1
0
mirror of https://github.com/bigchaindb/bigchaindb.git synced 2024-06-28 00:27:45 +02:00

s/fulfillments/inputs/g && s/conditions/outputs/g (code changes)

This commit is contained in:
Scott Sadler 2016-12-13 13:41:46 +01:00
parent e2e3ecb9f4
commit ed55b3984e
14 changed files with 639 additions and 669 deletions

View File

@ -95,13 +95,13 @@ def get_asset_by_id(connection, asset_id):
@register_query(RethinkDBConnection)
def get_spent(connection, transaction_id, condition_id):
def get_spent(connection, transaction_id, output_id):
# TODO: use index!
return connection.run(
r.table('bigchain', read_mode=READ_MODE)
.concat_map(lambda doc: doc['block']['transactions'])
.filter(lambda transaction: transaction['fulfillments'].contains(
lambda fulfillment: fulfillment['input'] == {'txid': transaction_id, 'cid': condition_id})))
.filter(lambda transaction: transaction['inputs'].contains(
lambda input: input['fulfills'] == {'txid': transaction_id, 'idx': output_id})))
@register_query(RethinkDBConnection)
@ -110,8 +110,8 @@ def get_owned_ids(connection, owner):
return connection.run(
r.table('bigchain', read_mode=READ_MODE)
.concat_map(lambda doc: doc['block']['transactions'])
.filter(lambda tx: tx['conditions'].contains(
lambda c: c['owners_after'].contains(owner))))
.filter(lambda tx: tx['outputs'].contains(
lambda c: c['public_keys'].contains(owner))))
@register_query(RethinkDBConnection)

View File

@ -79,7 +79,7 @@ class CyclicBlockchainError(Exception):
class TransactionNotInValidBlock(Exception):
"""Raised when a transfer transaction is attempting to fulfill the
conditions of a transaction that is in an invalid or undecided block"""
outputs of a transaction that is in an invalid or undecided block"""
class AssetIdMismatch(Exception):

View File

@ -88,11 +88,10 @@ definitions:
Type of the transaction:
A ``CREATE`` transaction creates an asset in BigchainDB. This
transaction has outputs (conditions) but no inputs (fulfillments),
so a dummy fulfillment is used.
transaction has outputs but no inputs, so a dummy fulfillment is used.
A ``TRANSFER`` transaction transfers ownership of an asset, by providing
fulfillments to conditions of earlier transactions.
fulfillments to outputs conditions of earlier transactions.
A ``GENESIS`` transaction is a special case transaction used as the
sole member of the first block in a BigchainDB ledger.

File diff suppressed because it is too large Load Diff

View File

@ -356,7 +356,7 @@ class Bigchain(object):
if cursor:
return Asset.from_dict(cursor[0]['asset'])
def get_spent(self, txid, cid):
def get_spent(self, txid, idx):
"""Check if a `txid` was already used as an input.
A transaction can be used as an input for another transaction. Bigchain needs to make sure that a
@ -364,15 +364,16 @@ class Bigchain(object):
Args:
txid (str): The id of the transaction
cid (num): the index of the condition in the respective transaction
idx (num): the index of the output in the respective transaction
Returns:
The transaction (Transaction) that used the `txid` as an input else
`None`
"""
# checks if an input was already spent
# checks if the bigchain has any transaction with input {'txid': ..., 'cid': ...}
transactions = list(backend.query.get_spent(self.connection, txid, cid))
# checks if the bigchain has any transaction with input {'txid': ...,
# 'idx': ...}
transactions = list(backend.query.get_spent(self.connection, txid, idx))
# a transaction_id should have been spent at most one time
if transactions:
@ -404,7 +405,7 @@ class Bigchain(object):
owner (str): base58 encoded public key.
Returns:
:obj:`list` of TransactionLink: list of ``txid`` s and ``cid`` s
:obj:`list` of TransactionLink: list of ``txid`` s and ``idx`` s
pointing to another transaction's condition
"""
@ -421,22 +422,22 @@ class Bigchain(object):
# NOTE: It's OK to not serialize the transaction here, as we do not
# use it after the execution of this function.
# a transaction can contain multiple outputs (conditions) so we need to iterate over all of them
# a transaction can contain multiple outputs so we need to iterate over all of them
# to get a list of outputs available to spend
for index, cond in enumerate(tx['conditions']):
for index, out in enumerate(tx['outputs']):
# for simple signature conditions there are no subfulfillments
# check if the owner is in the condition `owners_after`
if len(cond['owners_after']) == 1:
if cond['condition']['details']['public_key'] == owner:
if len(out['public_keys']) == 1:
if out['condition']['details']['public_key'] == owner:
tx_link = TransactionLink(tx['id'], index)
else:
# for transactions with multiple `owners_after` there will be several subfulfillments nested
# for transactions with multiple `public_keys` there will be several subfulfillments nested
# in the condition. We need to iterate the subfulfillments to make sure there is a
# subfulfillment for `owner`
if util.condition_details_has_owner(cond['condition']['details'], owner):
if util.condition_details_has_owner(out['condition']['details'], owner):
tx_link = TransactionLink(tx['id'], index)
# check if input was already spent
if not self.get_spent(tx_link.txid, tx_link.cid):
if not self.get_spent(tx_link.txid, tx_link.idx):
owned.append(tx_link)
return owned

View File

@ -33,18 +33,18 @@ class Transaction(Transaction):
InvalidHash: if the hash of the transaction is wrong
InvalidSignature: if the signature of the transaction is wrong
"""
if len(self.fulfillments) == 0:
raise ValueError('Transaction contains no fulfillments')
if len(self.inputs) == 0:
raise ValueError('Transaction contains no inputs')
input_conditions = []
inputs_defined = all([ffill.tx_input for ffill in self.fulfillments])
inputs_defined = all([inp.fulfills for inp in self.inputs])
if self.operation in (Transaction.CREATE, Transaction.GENESIS):
# validate inputs
if inputs_defined:
raise ValueError('A CREATE operation has no inputs')
# validate asset
amount = sum([condition.amount for condition in self.conditions])
amount = sum([out.amount for out in self.outputs])
self.asset.validate_asset(amount=amount)
elif self.operation == Transaction.TRANSFER:
if not inputs_defined:
@ -54,9 +54,9 @@ class Transaction(Transaction):
# store the inputs so that we can check if the asset ids match
input_txs = []
input_amount = 0
for ffill in self.fulfillments:
input_txid = ffill.tx_input.txid
input_cid = ffill.tx_input.cid
for input in self.inputs:
input_txid = input.fulfills.txid
input_idx = input.fulfills.idx
input_tx, status = bigchain.\
get_transaction(input_txid, include_status=True)
@ -69,23 +69,22 @@ class Transaction(Transaction):
'input `{}` does not exist in a valid block'.format(
input_txid))
spent = bigchain.get_spent(input_txid, ffill.tx_input.cid)
spent = bigchain.get_spent(input_txid, input_idx)
if spent and spent.id != self.id:
raise DoubleSpend('input `{}` was already spent'
.format(input_txid))
input_conditions.append(input_tx.conditions[input_cid])
input_conditions.append(input_tx.outputs[input_idx])
input_txs.append(input_tx)
if input_tx.conditions[input_cid].amount < 1:
if input_tx.outputs[input_idx].amount < 1:
raise AmountError('`amount` needs to be greater than zero')
input_amount += input_tx.conditions[input_cid].amount
input_amount += input_tx.outputs[input_idx].amount
# validate asset id
asset_id = Asset.get_asset_id(input_txs)
if asset_id != self.asset.data_id:
raise AssetIdMismatch(('The asset id of the input does not'
' match the asset id of the'
' transaction'))
raise AssetIdMismatch('The asset id of the input does not '
'match the asset id of the transaction')
# get the asset creation to see if its divisible or not
asset = bigchain.get_asset_by_id(asset_id)
@ -93,10 +92,10 @@ class Transaction(Transaction):
asset.validate_asset(amount=input_amount)
# validate the amounts
output_amount = 0
for condition in self.conditions:
if condition.amount < 1:
for output in self.outputs:
if output.amount < 1:
raise AmountError('`amount` needs to be greater than zero')
output_amount += condition.amount
output_amount += output.amount
if output_amount != input_amount:
raise AmountError(('The amount used in the inputs `{}`'
@ -109,7 +108,7 @@ class Transaction(Transaction):
raise TypeError('`operation`: `{}` must be either {}.'
.format(self.operation, allowed_operations))
if not self.fulfillments_valid(input_conditions):
if not self.inputs_valid(input_conditions):
raise InvalidSignature()
else:
return self

View File

@ -57,9 +57,9 @@ Transaction Schema
* `Transaction`_
* Condition_
* Input_
* Fulfillment_
* Output_
* Asset_
@ -71,15 +71,15 @@ Transaction
%(transaction)s
Condition
Input
----------
%(condition)s
%(input)s
Fulfillment
Output
-----------
%(fulfillment)s
%(output)s
Asset
-----
@ -99,8 +99,8 @@ def generate_transaction_docs():
doc = TPL_TRANSACTION % {
'transaction': render_section('Transaction', schema),
'condition': render_section('Condition', defs['condition']),
'fulfillment': render_section('Fulfillment', defs['fulfillment']),
'output': render_section('Output', defs['output']),
'input': render_section('Input', defs['input']),
'asset': render_section('Asset', defs['asset']),
'metadata': render_section('Metadata', defs['metadata']['anyOf'][0]),
'container': 'transaction-schema',

View File

@ -17,9 +17,9 @@ def test_single_in_single_own_single_out_single_own_create(b, user_pk):
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
assert len(tx_signed.outputs) == 1
assert tx_signed.outputs[0].amount == 100
assert len(tx_signed.inputs) == 1
# CREATE divisible asset
@ -37,10 +37,10 @@ def test_single_in_single_own_multiple_out_single_own_create(b, user_pk):
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
assert len(tx_signed.outputs) == 2
assert tx_signed.outputs[0].amount == 50
assert tx_signed.outputs[1].amount == 50
assert len(tx_signed.inputs) == 1
# CREATE divisible asset
@ -57,14 +57,14 @@ def test_single_in_single_own_single_out_multiple_own_create(b, user_pk):
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.outputs) == 1
assert tx_signed.outputs[0].amount == 100
condition = tx_signed.conditions[0].to_dict()
assert 'subfulfillments' in condition['condition']['details']
assert len(condition['condition']['details']['subfulfillments']) == 2
output = tx_signed.outputs[0].to_dict()
assert 'subfulfillments' in output['condition']['details']
assert len(output['condition']['details']['subfulfillments']) == 2
assert len(tx_signed.fulfillments) == 1
assert len(tx_signed.inputs) == 1
# CREATE divisible asset
@ -84,15 +84,15 @@ def test_single_in_single_own_multiple_out_mix_own_create(b, user_pk):
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.outputs) == 2
assert tx_signed.outputs[0].amount == 50
assert tx_signed.outputs[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
output_cid1 = tx_signed.outputs[1].to_dict()
assert 'subfulfillments' in output_cid1['condition']['details']
assert len(output_cid1['condition']['details']['subfulfillments']) == 2
assert len(tx_signed.fulfillments) == 1
assert len(tx_signed.inputs) == 1
# CREATE divisible asset
@ -108,11 +108,11 @@ def test_single_in_multiple_own_single_out_single_own_create(b, user_pk,
tx = Transaction.create([b.me, user_pk], [([user_pk], 100)], asset=asset)
tx_signed = tx.sign([b.me_private, user_sk])
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
assert len(tx_signed.outputs) == 1
assert tx_signed.outputs[0].amount == 100
assert len(tx_signed.inputs) == 1
ffill = tx_signed.fulfillments[0].fulfillment.to_dict()
ffill = tx_signed.inputs[0].fulfillment.to_dict()
assert 'subfulfillments' in ffill
assert len(ffill['subfulfillments']) == 2
@ -150,9 +150,9 @@ def test_single_in_single_own_single_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 1
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset
@ -185,10 +185,10 @@ def test_single_in_single_own_multiple_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2
assert tx_transfer_signed.conditions[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50
assert len(tx_transfer_signed.fulfillments) == 1
assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.outputs[1].amount == 50
assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset
@ -221,14 +221,14 @@ def test_single_in_single_own_single_out_multiple_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
condition = tx_transfer_signed.conditions[0].to_dict()
condition = tx_transfer_signed.outputs[0].to_dict()
assert 'subfulfillments' in condition['condition']['details']
assert len(condition['condition']['details']['subfulfillments']) == 2
assert len(tx_transfer_signed.fulfillments) == 1
assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset
@ -262,15 +262,15 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2
assert tx_transfer_signed.conditions[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50
assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.outputs[1].amount == 50
condition_cid1 = tx_transfer_signed.conditions[1].to_dict()
assert 'subfulfillments' in condition_cid1['condition']['details']
assert len(condition_cid1['condition']['details']['subfulfillments']) == 2
output_cid1 = tx_transfer_signed.outputs[1].to_dict()
assert 'subfulfillments' in output_cid1['condition']['details']
assert len(output_cid1['condition']['details']['subfulfillments']) == 2
assert len(tx_transfer_signed.fulfillments) == 1
assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset
@ -303,11 +303,11 @@ def test_single_in_multiple_own_single_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 1
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.inputs) == 1
ffill = tx_transfer_signed.fulfillments[0].fulfillment.to_dict()
ffill = tx_transfer_signed.inputs[0].fulfillment.to_dict()
assert 'subfulfillments' in ffill
assert len(ffill['subfulfillments']) == 2
@ -342,9 +342,9 @@ def test_multiple_in_single_own_single_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.inputs) == 2
# TRANSFER divisible asset
@ -379,12 +379,12 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.inputs) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict()
ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' in ffill_fid0
assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid0['subfulfillments']) == 2
@ -424,12 +424,12 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.inputs) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict()
ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' not in ffill_fid0
assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid1['subfulfillments']) == 2
@ -470,19 +470,19 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(b, user_pk,
tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2
assert tx_transfer_signed.conditions[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50
assert len(tx_transfer_signed.fulfillments) == 2
assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.outputs[1].amount == 50
assert len(tx_transfer_signed.inputs) == 2
cond_cid0 = tx_transfer_signed.conditions[0].to_dict()
cond_cid1 = tx_transfer_signed.conditions[1].to_dict()
cond_cid0 = tx_transfer_signed.outputs[0].to_dict()
cond_cid1 = tx_transfer_signed.outputs[1].to_dict()
assert 'subfulfillments' not in cond_cid0['condition']['details']
assert 'subfulfillments' in cond_cid1['condition']['details']
assert len(cond_cid1['condition']['details']['subfulfillments']) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict()
ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' not in ffill_fid0
assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid1['subfulfillments']) == 2
@ -541,12 +541,12 @@ def test_multiple_in_different_transactions(b, user_pk, user_sk):
tx_transfer2_signed = tx_transfer2.sign([user_sk])
assert tx_transfer2_signed.validate(b) == tx_transfer2_signed
assert len(tx_transfer2_signed.conditions) == 1
assert tx_transfer2_signed.conditions[0].amount == 100
assert len(tx_transfer2_signed.fulfillments) == 2
assert len(tx_transfer2_signed.outputs) == 1
assert tx_transfer2_signed.outputs[0].amount == 100
assert len(tx_transfer2_signed.inputs) == 2
fid0_input = tx_transfer2_signed.fulfillments[0].to_dict()['input']['txid']
fid1_input = tx_transfer2_signed.fulfillments[1].to_dict()['input']['txid']
fid0_input = tx_transfer2_signed.inputs[0].fulfills.txid
fid1_input = tx_transfer2_signed.inputs[1].fulfills.txid
assert fid0_input == tx_create.id
assert fid1_input == tx_transfer1.id
@ -651,8 +651,8 @@ def test_sum_amount(b, user_pk, user_sk):
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1
assert tx_transfer_signed.conditions[0].amount == 3
assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.outputs[0].amount == 3
@pytest.mark.usefixtures('inputs')
@ -681,9 +681,9 @@ def test_divide(b, user_pk, user_sk):
tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 3
for condition in tx_transfer_signed.conditions:
assert condition.amount == 1
assert len(tx_transfer_signed.outputs) == 3
for output in tx_transfer_signed.outputs:
assert output.amount == 1
# Check that negative inputs are caught when creating a TRANSFER transaction
@ -737,7 +737,7 @@ def test_non_positive_amounts_on_transfer_validate(b, user_pk, user_sk):
tx_transfer = Transaction.transfer(tx_create.to_inputs(),
[([b.me], 4), ([b.me], 1)],
asset=tx_create.asset)
tx_transfer.conditions[1].amount = -1
tx_transfer.outputs[1].amount = -1
tx_transfer_signed = tx_transfer.sign([user_sk])
with pytest.raises(AmountError):
@ -769,7 +769,7 @@ def test_non_positive_amounts_on_create_validate(b, user_pk):
asset = Asset(divisible=True)
tx_create = Transaction.create([b.me], [([user_pk], 3)],
asset=asset)
tx_create.conditions[0].amount = -3
tx_create.outputs[0].amount = -3
with patch.object(Asset, 'validate_asset', return_value=None):
tx_create_signed = tx_create.sign([b.me_private])

View File

@ -86,39 +86,39 @@ def user2_Ed25519(user2_pub):
@pytest.fixture
def user_ffill(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Fulfillment
return Fulfillment(user_Ed25519, [user_pub])
def user_input(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Input
return Input(user_Ed25519, [user_pub])
@pytest.fixture
def user2_ffill(user2_Ed25519, user2_pub):
from bigchaindb.common.transaction import Fulfillment
return Fulfillment(user2_Ed25519, [user2_pub])
def user2_input(user2_Ed25519, user2_pub):
from bigchaindb.common.transaction import Input
return Input(user2_Ed25519, [user2_pub])
@pytest.fixture
def user_user2_threshold_cond(user_user2_threshold, user_pub, user2_pub):
from bigchaindb.common.transaction import Condition
return Condition(user_user2_threshold, [user_pub, user2_pub])
def user_user2_threshold_output(user_user2_threshold, user_pub, user2_pub):
from bigchaindb.common.transaction import Output
return Output(user_user2_threshold, [user_pub, user2_pub])
@pytest.fixture
def user_user2_threshold_ffill(user_user2_threshold, user_pub, user2_pub):
from bigchaindb.common.transaction import Fulfillment
return Fulfillment(user_user2_threshold, [user_pub, user2_pub])
def user_user2_threshold_input(user_user2_threshold, user_pub, user2_pub):
from bigchaindb.common.transaction import Input
return Input(user_user2_threshold, [user_pub, user2_pub])
@pytest.fixture
def user_cond(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Condition
return Condition(user_Ed25519, [user_pub])
def user_output(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Output
return Output(user_Ed25519, [user_pub])
@pytest.fixture
def user2_cond(user2_Ed25519, user2_pub):
from bigchaindb.common.transaction import Condition
return Condition(user2_Ed25519, [user2_pub])
def user2_output(user2_Ed25519, user2_pub):
from bigchaindb.common.transaction import Output
return Output(user2_Ed25519, [user2_pub])
@pytest.fixture
@ -137,9 +137,10 @@ def uuid4():
@pytest.fixture
def utx(user_ffill, user_cond):
def utx(user_input, user_output):
from bigchaindb.common.transaction import Transaction, Asset
return Transaction(Transaction.CREATE, Asset(), [user_ffill], [user_cond])
return Transaction(Transaction.CREATE, Asset(), [user_input],
[user_output])
@pytest.fixture
@ -148,14 +149,14 @@ def tx(utx, user_priv):
@pytest.fixture
def transfer_utx(user_cond, user2_cond, utx):
from bigchaindb.common.transaction import (Fulfillment, TransactionLink,
def transfer_utx(user_output, user2_output, utx):
from bigchaindb.common.transaction import (Input, TransactionLink,
Transaction, Asset)
user_cond = user_cond.to_dict()
ffill = Fulfillment(utx.conditions[0].fulfillment,
user_cond['owners_after'],
TransactionLink(utx.id, 0))
return Transaction('TRANSFER', Asset(), [ffill], [user2_cond])
user_output = user_output.to_dict()
input = Input(utx.outputs[0].fulfillment,
user_output['public_keys'],
TransactionLink(utx.id, 0))
return Transaction('TRANSFER', Asset(), [input], [user2_output])
@pytest.fixture

View File

@ -2,111 +2,110 @@ from pytest import raises
from unittest.mock import patch
def test_fulfillment_serialization(ffill_uri, user_pub):
from bigchaindb.common.transaction import Fulfillment
from cryptoconditions import Fulfillment as CCFulfillment
def test_input_serialization(ffill_uri, user_pub):
from bigchaindb.common.transaction import Input
from cryptoconditions import Fulfillment
expected = {
'owners_before': [user_pub],
'fulfillment': ffill_uri,
'input': None,
'fulfills': None,
}
ffill = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub])
assert ffill.to_dict() == expected
input = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
assert input.to_dict() == expected
def test_fulfillment_deserialization_with_uri(ffill_uri, user_pub):
from bigchaindb.common.transaction import Fulfillment
from cryptoconditions import Fulfillment as CCFulfillment
def test_input_deserialization_with_uri(ffill_uri, user_pub):
from bigchaindb.common.transaction import Input
from cryptoconditions import Fulfillment
expected = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub])
expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
ffill = {
'owners_before': [user_pub],
'fulfillment': ffill_uri,
'input': None,
'fulfills': None,
}
ffill = Fulfillment.from_dict(ffill)
input = Input.from_dict(ffill)
assert ffill == expected
assert input == expected
def test_fulfillment_deserialization_with_invalid_fulfillment(user_pub):
from bigchaindb.common.transaction import Fulfillment
def test_input_deserialization_with_invalid_fulfillment(user_pub):
from bigchaindb.common.transaction import Input
ffill = {
'owners_before': [user_pub],
'fulfillment': None,
'input': None,
'fulfills': None,
}
with raises(TypeError):
Fulfillment.from_dict(ffill)
Input.from_dict(ffill)
def test_fulfillment_deserialization_with_invalid_fulfillment_uri(user_pub):
def test_input_deserialization_with_invalid_fulfillment_uri(user_pub):
from bigchaindb.common.exceptions import InvalidSignature
from bigchaindb.common.transaction import Fulfillment
from bigchaindb.common.transaction import Input
ffill = {
'owners_before': [user_pub],
'fulfillment': 'an invalid fulfillment',
'input': None,
'fulfills': None,
}
with raises(InvalidSignature):
Fulfillment.from_dict(ffill)
Input.from_dict(ffill)
def test_fulfillment_deserialization_with_unsigned_fulfillment(ffill_uri,
user_pub):
from bigchaindb.common.transaction import Fulfillment
from cryptoconditions import Fulfillment as CCFulfillment
def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub):
from bigchaindb.common.transaction import Input
from cryptoconditions import Fulfillment
expected = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub])
expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
ffill = {
'owners_before': [user_pub],
'fulfillment': CCFulfillment.from_uri(ffill_uri),
'input': None,
'fulfillment': Fulfillment.from_uri(ffill_uri),
'fulfills': None,
}
ffill = Fulfillment.from_dict(ffill)
input = Input.from_dict(ffill)
assert ffill == expected
assert input == expected
def test_condition_serialization(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
expected = {
'condition': {
'uri': user_Ed25519.condition_uri,
'details': user_Ed25519.to_dict(),
},
'owners_after': [user_pub],
'public_keys': [user_pub],
'amount': 1,
}
cond = Condition(user_Ed25519, [user_pub], 1)
cond = Output(user_Ed25519, [user_pub], 1)
assert cond.to_dict() == expected
def test_condition_deserialization(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
expected = Condition(user_Ed25519, [user_pub], 1)
expected = Output(user_Ed25519, [user_pub], 1)
cond = {
'condition': {
'uri': user_Ed25519.condition_uri,
'details': user_Ed25519.to_dict()
},
'owners_after': [user_pub],
'public_keys': [user_pub],
'amount': 1,
}
cond = Condition.from_dict(cond)
cond = Output.from_dict(cond)
assert cond == expected
def test_condition_hashlock_serialization():
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import PreimageSha256Fulfillment
secret = b'wow much secret'
@ -116,44 +115,44 @@ def test_condition_hashlock_serialization():
'condition': {
'uri': hashlock,
},
'owners_after': None,
'public_keys': None,
'amount': 1,
}
cond = Condition(hashlock, amount=1)
cond = Output(hashlock, amount=1)
assert cond.to_dict() == expected
def test_condition_hashlock_deserialization():
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import PreimageSha256Fulfillment
secret = b'wow much secret'
hashlock = PreimageSha256Fulfillment(preimage=secret).condition_uri
expected = Condition(hashlock, amount=1)
expected = Output(hashlock, amount=1)
cond = {
'condition': {
'uri': hashlock
},
'owners_after': None,
'public_keys': None,
'amount': 1,
}
cond = Condition.from_dict(cond)
cond = Output.from_dict(cond)
assert cond == expected
def test_invalid_condition_initialization(cond_uri, user_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
with raises(TypeError):
Condition(cond_uri, user_pub)
Output(cond_uri, user_pub)
def test_generate_conditions_split_half_recursive(user_pub, user2_pub,
user3_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub)
@ -167,13 +166,13 @@ def test_generate_conditions_split_half_recursive(user_pub, user2_pub,
expected_threshold.add_subfulfillment(expected_simple3)
expected.add_subfulfillment(expected_threshold)
cond = Condition.generate([user_pub, [user2_pub, expected_simple3]], 1)
cond = Output.generate([user_pub, [user2_pub, expected_simple3]], 1)
assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_split_half_single_owner(user_pub, user2_pub,
user3_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub)
@ -187,12 +186,12 @@ def test_generate_conditions_split_half_single_owner(user_pub, user2_pub,
expected.add_subfulfillment(expected_threshold)
expected.add_subfulfillment(expected_simple1)
cond = Condition.generate([[expected_simple2, user3_pub], user_pub], 1)
cond = Output.generate([[expected_simple2, user3_pub], user_pub], 1)
assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_flat_ownage(user_pub, user2_pub, user3_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub)
@ -204,42 +203,42 @@ def test_generate_conditions_flat_ownage(user_pub, user2_pub, user3_pub):
expected.add_subfulfillment(expected_simple2)
expected.add_subfulfillment(expected_simple3)
cond = Condition.generate([user_pub, user2_pub, expected_simple3], 1)
cond = Output.generate([user_pub, user2_pub, expected_simple3], 1)
assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_single_owner(user_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment
expected = Ed25519Fulfillment(public_key=user_pub)
cond = Condition.generate([user_pub], 1)
cond = Output.generate([user_pub], 1)
assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_single_owner_with_condition(user_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment
expected = Ed25519Fulfillment(public_key=user_pub)
cond = Condition.generate([expected], 1)
cond = Output.generate([expected], 1)
assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_invalid_parameters(user_pub, user2_pub,
user3_pub):
from bigchaindb.common.transaction import Condition
from bigchaindb.common.transaction import Output
with raises(ValueError):
Condition.generate([], 1)
Output.generate([], 1)
with raises(TypeError):
Condition.generate('not a list', 1)
Output.generate('not a list', 1)
with raises(ValueError):
Condition.generate([[user_pub, [user2_pub, [user3_pub]]]], 1)
Output.generate([[user_pub, [user2_pub, [user3_pub]]]], 1)
with raises(ValueError):
Condition.generate([[user_pub]], 1)
Output.generate([[user_pub]], 1)
def test_invalid_transaction_initialization():
@ -253,21 +252,21 @@ def test_invalid_transaction_initialization():
Transaction(
operation='CREATE',
asset=Asset(),
conditions='invalid conditions'
outputs='invalid outputs'
)
with raises(TypeError):
Transaction(
operation='CREATE',
asset=Asset(),
conditions=[],
fulfillments='invalid fulfillments'
outputs=[],
inputs='invalid inputs'
)
with raises(TypeError):
Transaction(
operation='CREATE',
asset=Asset(),
conditions=[],
fulfillments=[],
outputs=[],
inputs=[],
metadata='invalid metadata'
)
@ -291,7 +290,7 @@ def test_create_default_asset_on_tx_initialization():
validate_transaction_model(tx)
def test_transaction_serialization(user_ffill, user_cond, data, data_id):
def test_transaction_serialization(user_input, user_output, data, data_id):
from bigchaindb.common.transaction import Transaction, Asset
from bigchaindb.common.exceptions import ValidationError
from .util import validate_transaction_model
@ -301,10 +300,10 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
expected = {
'id': tx_id,
'version': Transaction.VERSION,
# NOTE: This test assumes that Fulfillments and Conditions can
# NOTE: This test assumes that Inputs and Outputs can
# successfully be serialized
'fulfillments': [user_ffill.to_dict()],
'conditions': [user_cond.to_dict()],
'inputs': [user_input.to_dict()],
'outputs': [user_output.to_dict()],
'operation': Transaction.CREATE,
'metadata': None,
'asset': {
@ -316,8 +315,8 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
}
}
tx = Transaction(Transaction.CREATE, Asset(data, data_id), [user_ffill],
[user_cond])
tx = Transaction(Transaction.CREATE, Asset(data, data_id), [user_input],
[user_output])
tx_dict = tx.to_dict()
tx_dict['id'] = tx_id
tx_dict['asset']['id'] = data_id
@ -329,21 +328,20 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
validate_transaction_model(tx)
def test_transaction_deserialization(user_ffill, user_cond, data, uuid4):
def test_transaction_deserialization(user_input, user_output, data, uuid4):
from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model
expected_asset = Asset(data, uuid4)
expected = Transaction(Transaction.CREATE, expected_asset, [user_ffill],
[user_cond], None, Transaction.VERSION)
expected = Transaction(Transaction.CREATE, expected_asset, [user_input],
[user_output], None, Transaction.VERSION)
tx = {
'version': Transaction.VERSION,
# NOTE: This test assumes that Fulfillments and Conditions can
# NOTE: This test assumes that Inputs and Outputs can
# successfully be serialized
'fulfillments': [user_ffill.to_dict()],
'conditions': [user_cond.to_dict()],
'inputs': [user_input.to_dict()],
'outputs': [user_output.to_dict()],
'operation': Transaction.CREATE,
'metadata': None,
'asset': {
@ -374,13 +372,11 @@ def test_tx_serialization_with_incorrect_hash(utx):
utx_dict.pop('id')
def test_invalid_fulfillment_initialization(user_ffill, user_pub):
from bigchaindb.common.transaction import Fulfillment
def test_invalid_fulfillment_initialization(user_input, user_pub):
from bigchaindb.common.transaction import Input
with raises(TypeError):
Fulfillment(user_ffill, user_pub)
with raises(TypeError):
Fulfillment(user_ffill, [], tx_input='somethingthatiswrong')
Input(user_input, tx_input='somethingthatiswrong')
def test_transaction_link_serialization():
@ -389,7 +385,7 @@ def test_transaction_link_serialization():
tx_id = 'a transaction id'
expected = {
'txid': tx_id,
'cid': 0,
'idx': 0,
}
tx_link = TransactionLink(tx_id, 0)
@ -412,7 +408,7 @@ def test_transaction_link_deserialization():
expected = TransactionLink(tx_id, 0)
tx_link = {
'txid': tx_id,
'cid': 0,
'idx': 0,
}
tx_link = TransactionLink.from_dict(tx_link)
@ -517,45 +513,45 @@ def test_eq_asset_link():
assert AssetLink(asset_id_1) != AssetLink(asset_id_2)
def test_add_fulfillment_to_tx(user_ffill):
def test_add_input_to_tx(user_input):
from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset(), [], [])
tx.add_fulfillment(user_ffill)
tx.add_input(user_input)
assert len(tx.fulfillments) == 1
assert len(tx.inputs) == 1
def test_add_fulfillment_to_tx_with_invalid_parameters():
def test_add_input_to_tx_with_invalid_parameters():
from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset())
with raises(TypeError):
tx.add_fulfillment('somewronginput')
tx.add_input('somewronginput')
def test_add_condition_to_tx(user_cond):
def test_add_output_to_tx(user_output):
from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset())
tx.add_condition(user_cond)
tx.add_output(user_output)
assert len(tx.conditions) == 1
assert len(tx.outputs) == 1
validate_transaction_model(tx)
def test_add_condition_to_tx_with_invalid_parameters():
def test_add_output_to_tx_with_invalid_parameters():
from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset(), [], [])
with raises(TypeError):
tx.add_condition('somewronginput')
tx.add_output('somewronginput')
def test_sign_with_invalid_parameters(utx, user_priv):
@ -565,67 +561,60 @@ def test_sign_with_invalid_parameters(utx, user_priv):
utx.sign(user_priv)
def test_validate_tx_simple_create_signature(user_ffill, user_cond, user_priv):
def test_validate_tx_simple_create_signature(user_input, user_output, user_priv):
from copy import deepcopy
from bigchaindb.common.crypto import PrivateKey
from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(), [user_ffill], [user_cond])
expected = deepcopy(user_cond)
tx = Transaction(Transaction.CREATE, Asset(), [user_input], [user_output])
expected = deepcopy(user_output)
expected.fulfillment.sign(str(tx).encode(), PrivateKey(user_priv))
tx.sign([user_priv])
assert tx.fulfillments[0].to_dict()['fulfillment'] == \
assert tx.inputs[0].to_dict()['fulfillment'] == \
expected.fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True
assert tx.inputs_valid() is True
validate_transaction_model(tx)
def test_invoke_simple_signature_fulfillment_with_invalid_params(utx,
user_ffill):
user_input):
from bigchaindb.common.exceptions import KeypairMismatchException
with raises(KeypairMismatchException):
invalid_key_pair = {'wrong_pub_key': 'wrong_priv_key'}
utx._sign_simple_signature_fulfillment(user_ffill,
utx._sign_simple_signature_fulfillment(user_input,
0,
'somemessage',
invalid_key_pair)
def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_ffill,
def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input,
user3_pub, user3_priv):
from bigchaindb.common.exceptions import KeypairMismatchException
with raises(KeypairMismatchException):
utx._sign_threshold_signature_fulfillment(user_user2_threshold_ffill,
utx._sign_threshold_signature_fulfillment(user_user2_threshold_input,
0,
'somemessage',
{user3_pub: user3_priv})
with raises(KeypairMismatchException):
user_user2_threshold_ffill.owners_before = ['somewrongvalue']
utx._sign_threshold_signature_fulfillment(user_user2_threshold_ffill,
0,
'somemessage',
None)
def test_validate_fulfillment_with_invalid_parameters(utx):
from bigchaindb.common.transaction import Transaction
input_conditions = [cond.fulfillment.condition_uri for cond
in utx.conditions]
input_conditions = [out.fulfillment.condition_uri for out in utx.outputs]
tx_dict = utx.to_dict()
tx_dict = Transaction._remove_signatures(tx_dict)
tx_serialized = Transaction._to_str(tx_dict)
assert utx._fulfillment_valid(utx.fulfillments[0],
assert utx._input_valid(utx.inputs[0],
tx_serialized,
input_conditions) is False
def test_validate_multiple_fulfillments(user_ffill, user_cond, user_priv):
def test_validate_multiple_inputs(user_input, user_output, user_priv):
from copy import deepcopy
from bigchaindb.common.crypto import PrivateKey
@ -633,33 +622,33 @@ def test_validate_multiple_fulfillments(user_ffill, user_cond, user_priv):
from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(divisible=True),
[user_ffill, deepcopy(user_ffill)],
[user_cond, deepcopy(user_cond)])
[user_input, deepcopy(user_input)],
[user_output, deepcopy(user_output)])
expected_first = deepcopy(tx)
expected_second = deepcopy(tx)
expected_first.fulfillments = [expected_first.fulfillments[0]]
expected_second.fulfillments = [expected_second.fulfillments[1]]
expected_first.inputs = [expected_first.inputs[0]]
expected_second.inputs = [expected_second.inputs[1]]
expected_first_bytes = str(expected_first).encode()
expected_first.fulfillments[0].fulfillment.sign(expected_first_bytes,
expected_first.inputs[0].fulfillment.sign(expected_first_bytes,
PrivateKey(user_priv))
expected_second_bytes = str(expected_second).encode()
expected_second.fulfillments[0].fulfillment.sign(expected_second_bytes,
PrivateKey(user_priv))
expected_second.inputs[0].fulfillment.sign(expected_second_bytes,
PrivateKey(user_priv))
tx.sign([user_priv])
assert tx.fulfillments[0].to_dict()['fulfillment'] == \
expected_first.fulfillments[0].fulfillment.serialize_uri()
assert tx.fulfillments[1].to_dict()['fulfillment'] == \
expected_second.fulfillments[0].fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True
assert tx.inputs[0].to_dict()['fulfillment'] == \
expected_first.inputs[0].fulfillment.serialize_uri()
assert tx.inputs[1].to_dict()['fulfillment'] == \
expected_second.inputs[0].fulfillment.serialize_uri()
assert tx.inputs_valid() is True
validate_transaction_model(tx)
def test_validate_tx_threshold_create_signature(user_user2_threshold_ffill,
user_user2_threshold_cond,
def test_validate_tx_threshold_create_signature(user_user2_threshold_input,
user_user2_threshold_output,
user_pub,
user2_pub,
user_priv,
@ -670,83 +659,78 @@ def test_validate_tx_threshold_create_signature(user_user2_threshold_ffill,
from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(), [user_user2_threshold_ffill],
[user_user2_threshold_cond])
expected = deepcopy(user_user2_threshold_cond)
tx = Transaction(Transaction.CREATE, Asset(), [user_user2_threshold_input],
[user_user2_threshold_output])
expected = deepcopy(user_user2_threshold_output)
expected.fulfillment.subconditions[0]['body'].sign(str(tx).encode(),
PrivateKey(user_priv))
expected.fulfillment.subconditions[1]['body'].sign(str(tx).encode(),
PrivateKey(user2_priv))
tx.sign([user_priv, user2_priv])
assert tx.fulfillments[0].to_dict()['fulfillment'] == \
assert tx.inputs[0].to_dict()['fulfillment'] == \
expected.fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True
assert tx.inputs_valid() is True
validate_transaction_model(tx)
def test_multiple_fulfillment_validation_of_transfer_tx(user_ffill, user_cond,
user_priv, user2_pub,
user2_priv, user3_pub,
user3_priv):
def test_multiple_input_validation_of_transfer_tx(user_input, user_output,
user_priv, user2_pub,
user2_priv, user3_pub,
user3_priv):
from copy import deepcopy
from bigchaindb.common.transaction import (Transaction, TransactionLink,
Fulfillment, Condition, Asset)
Input, Output, Asset)
from cryptoconditions import Ed25519Fulfillment
from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(divisible=True),
[user_ffill, deepcopy(user_ffill)],
[user_cond, deepcopy(user_cond)])
[user_input, deepcopy(user_input)],
[user_output, deepcopy(user_output)])
tx.sign([user_priv])
fulfillments = [Fulfillment(cond.fulfillment, cond.owners_after,
TransactionLink(tx.id, index))
for index, cond in enumerate(tx.conditions)]
conditions = [Condition(Ed25519Fulfillment(public_key=user3_pub),
[user3_pub]),
Condition(Ed25519Fulfillment(public_key=user3_pub),
[user3_pub])]
transfer_tx = Transaction('TRANSFER', tx.asset, fulfillments, conditions)
inputs = [Input(cond.fulfillment, cond.public_keys,
TransactionLink(tx.id, index))
for index, cond in enumerate(tx.outputs)]
outputs = [Output(Ed25519Fulfillment(public_key=user3_pub), [user3_pub]),
Output(Ed25519Fulfillment(public_key=user3_pub), [user3_pub])]
transfer_tx = Transaction('TRANSFER', tx.asset, inputs, outputs)
transfer_tx = transfer_tx.sign([user_priv])
assert transfer_tx.fulfillments_valid(tx.conditions) is True
assert transfer_tx.inputs_valid(tx.outputs) is True
validate_transaction_model(tx)
def test_validate_fulfillments_of_transfer_tx_with_invalid_params(transfer_tx,
cond_uri,
utx,
user2_pub,
user_priv):
from bigchaindb.common.transaction import Condition
def test_validate_inputs_of_transfer_tx_with_invalid_params(
transfer_tx, cond_uri, utx, user2_pub, user_priv):
from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment
invalid_cond = Condition(Ed25519Fulfillment.from_uri('cf:0:'), ['invalid'])
assert transfer_tx.fulfillments_valid([invalid_cond]) is False
invalid_cond = utx.conditions[0]
invalid_cond.owners_after = 'invalid'
assert transfer_tx.fulfillments_valid([invalid_cond]) is True
invalid_out = Output(Ed25519Fulfillment.from_uri('cf:0:'), ['invalid'])
assert transfer_tx.inputs_valid([invalid_out]) is False
invalid_out = utx.outputs[0]
invalid_out.public_key = 'invalid'
assert transfer_tx.inputs_valid([invalid_out]) is True
with raises(TypeError):
assert transfer_tx.fulfillments_valid(None) is False
assert transfer_tx.inputs_valid(None) is False
with raises(AttributeError):
transfer_tx.fulfillments_valid('not a list')
transfer_tx.inputs_valid('not a list')
with raises(ValueError):
transfer_tx.fulfillments_valid([])
transfer_tx.inputs_valid([])
with raises(TypeError):
transfer_tx.operation = "Operation that doesn't exist"
transfer_tx.fulfillments_valid([utx.conditions[0]])
transfer_tx.inputs_valid([utx.outputs[0]])
def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
def test_create_create_transaction_single_io(user_output, user_pub, data, uuid4):
from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model
expected = {
'conditions': [user_cond.to_dict()],
'outputs': [user_output.to_dict()],
'metadata': data,
'asset': {
'id': uuid4,
@ -755,13 +739,13 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
'refillable': False,
'data': data,
},
'fulfillments': [
'inputs': [
{
'owners_before': [
user_pub
],
'fulfillment': None,
'input': None
'fulfills': None
}
],
'operation': 'CREATE',
@ -771,7 +755,7 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
asset = Asset(data, uuid4)
tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset)
tx_dict = tx.to_dict()
tx_dict['fulfillments'][0]['fulfillment'] = None
tx_dict['inputs'][0]['fulfillment'] = None
tx_dict.pop('id')
assert tx_dict == expected
@ -784,23 +768,23 @@ def test_validate_single_io_create_transaction(user_pub, user_priv, data):
tx = Transaction.create([user_pub], [([user_pub], 1)], data, Asset())
tx = tx.sign([user_priv])
assert tx.fulfillments_valid() is True
assert tx.inputs_valid() is True
def test_create_create_transaction_multiple_io(user_cond, user2_cond, user_pub,
def test_create_create_transaction_multiple_io(user_output, user2_output, user_pub,
user2_pub):
from bigchaindb.common.transaction import Transaction, Asset, Fulfillment
from bigchaindb.common.transaction import Transaction, Asset, Input
# a fulfillment for a create transaction with multiple `owners_before`
# is a fulfillment for an implicit threshold condition with
# weight = len(owners_before)
ffill = Fulfillment.generate([user_pub, user2_pub]).to_dict()
input = Input.generate([user_pub, user2_pub]).to_dict()
expected = {
'conditions': [user_cond.to_dict(), user2_cond.to_dict()],
'outputs': [user_output.to_dict(), user2_output.to_dict()],
'metadata': {
'message': 'hello'
},
'fulfillments': [ffill],
'inputs': [input],
'operation': 'CREATE',
'version': 1
}
@ -825,19 +809,19 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv,
metadata={'message': 'hello'},
asset=Asset(divisible=True))
tx = tx.sign([user_priv, user2_priv])
assert tx.fulfillments_valid() is True
assert tx.inputs_valid() is True
validate_transaction_model(tx)
def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
user_user2_threshold_cond,
user_user2_threshold_ffill, data,
user_user2_threshold_output,
user_user2_threshold_input, data,
uuid4):
from bigchaindb.common.transaction import Transaction, Asset
expected = {
'conditions': [user_user2_threshold_cond.to_dict()],
'outputs': [user_user2_threshold_output.to_dict()],
'metadata': data,
'asset': {
'id': uuid4,
@ -846,13 +830,13 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
'refillable': False,
'data': data,
},
'fulfillments': [
'inputs': [
{
'owners_before': [
user_pub,
user_pub
],
'fulfillment': None,
'input': None
'fulfills': None
},
],
'operation': 'CREATE',
@ -863,7 +847,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
data, asset)
tx_dict = tx.to_dict()
tx_dict.pop('id')
tx_dict['fulfillments'][0]['fulfillment'] = None
tx_dict['inputs'][0]['fulfillment'] = None
assert tx_dict == expected
@ -876,7 +860,7 @@ def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub,
tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)],
data, Asset())
tx = tx.sign([user_priv])
assert tx.fulfillments_valid() is True
assert tx.inputs_valid() is True
validate_transaction_model(tx)
@ -898,18 +882,18 @@ def test_create_create_transaction_with_invalid_parameters(user_pub):
Transaction.create([user_pub], [([user_pub],)])
def test_conditions_to_inputs(tx):
ffills = tx.to_inputs([0])
assert len(ffills) == 1
ffill = ffills.pop()
assert ffill.fulfillment == tx.conditions[0].fulfillment
assert ffill.owners_before == tx.conditions[0].owners_after
assert ffill.tx_input.txid == tx.id
assert ffill.tx_input.cid == 0
def test_outputs_to_inputs(tx):
inputs = tx.to_inputs([0])
assert len(inputs) == 1
input = inputs.pop()
assert input.owners_before == tx.outputs[0].public_keys
assert input.fulfillment == tx.outputs[0].fulfillment
assert input.fulfills.txid == tx.id
assert input.fulfills.idx == 0
def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub,
user2_cond, user_priv, uuid4):
user2_output, user_priv, uuid4):
from copy import deepcopy
from bigchaindb.common.crypto import PrivateKey
from bigchaindb.common.transaction import Transaction, Asset
@ -917,20 +901,20 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub,
from .util import validate_transaction_model
expected = {
'conditions': [user2_cond.to_dict()],
'outputs': [user2_output.to_dict()],
'metadata': None,
'asset': {
'id': uuid4,
},
'fulfillments': [
'inputs': [
{
'owners_before': [
user_pub
],
'fulfillment': None,
'input': {
'fulfills': {
'txid': tx.id,
'cid': 0
'idx': 0
}
}
],
@ -948,19 +932,19 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub,
expected_input.fulfillment.sign(serialize(expected).encode(),
PrivateKey(user_priv))
expected_ffill = expected_input.fulfillment.serialize_uri()
transfer_ffill = transfer_tx['fulfillments'][0]['fulfillment']
transfer_ffill = transfer_tx['inputs'][0]['fulfillment']
assert transfer_ffill == expected_ffill
transfer_tx = Transaction.from_dict(transfer_tx)
assert transfer_tx.fulfillments_valid([tx.conditions[0]]) is True
assert transfer_tx.inputs_valid([tx.outputs[0]]) is True
validate_transaction_model(transfer_tx)
def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
user2_pub, user2_priv,
user3_pub, user2_cond):
user3_pub, user2_output):
from bigchaindb.common.transaction import Transaction, Asset
asset = Asset(divisible=True)
@ -969,26 +953,26 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
tx = tx.sign([user_priv])
expected = {
'conditions': [user2_cond.to_dict(), user2_cond.to_dict()],
'outputs': [user2_output.to_dict(), user2_output.to_dict()],
'metadata': None,
'fulfillments': [
'inputs': [
{
'owners_before': [
user_pub
],
'fulfillment': None,
'input': {
'fulfills': {
'txid': tx.id,
'cid': 0
'idx': 0
}
}, {
'owners_before': [
user2_pub
],
'fulfillment': None,
'input': {
'fulfills': {
'txid': tx.id,
'cid': 1
'idx': 1
}
}
],
@ -1001,14 +985,14 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
asset=tx.asset)
transfer_tx = transfer_tx.sign([user_priv, user2_priv])
assert len(transfer_tx.fulfillments) == 2
assert len(transfer_tx.conditions) == 2
assert len(transfer_tx.inputs) == 2
assert len(transfer_tx.outputs) == 2
assert transfer_tx.fulfillments_valid(tx.conditions) is True
assert transfer_tx.inputs_valid(tx.outputs) is True
transfer_tx = transfer_tx.to_dict()
transfer_tx['fulfillments'][0]['fulfillment'] = None
transfer_tx['fulfillments'][1]['fulfillment'] = None
transfer_tx['inputs'][0]['fulfillment'] = None
transfer_tx['inputs'][1]['fulfillment'] = None
transfer_tx.pop('asset')
transfer_tx.pop('id')
@ -1038,7 +1022,7 @@ def test_cant_add_empty_condition():
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, None)
with raises(TypeError):
tx.add_condition(None)
tx.add_output(None)
def test_cant_add_empty_fulfillment():
@ -1047,4 +1031,4 @@ def test_cant_add_empty_fulfillment():
with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, None)
with raises(TypeError):
tx.add_fulfillment(None)
tx.add_input(None)

View File

@ -276,7 +276,7 @@ class TestBigchainApi(object):
assert len(block['block']['transactions']) == 1
assert block['block']['transactions'][0]['operation'] == 'GENESIS'
assert block['block']['transactions'][0]['fulfillments'][0]['input'] is None
assert block['block']['transactions'][0]['inputs'][0]['fulfills'] is None
def test_create_genesis_block_fails_if_table_not_empty(self, b):
from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError
@ -527,16 +527,16 @@ class TestBigchainApi(object):
def test_non_create_input_not_found(self, b, user_pk):
from cryptoconditions import Ed25519Fulfillment
from bigchaindb.common.exceptions import TransactionDoesNotExist
from bigchaindb.common.transaction import (Fulfillment, Asset,
from bigchaindb.common.transaction import (Input, Asset,
TransactionLink)
from bigchaindb.models import Transaction
from bigchaindb import Bigchain
# Create a fulfillment for a non existing transaction
fulfillment = Fulfillment(Ed25519Fulfillment(public_key=user_pk),
[user_pk],
TransactionLink('somethingsomething', 0))
tx = Transaction.transfer([fulfillment], [([user_pk], 1)], Asset())
# Create an input for a non existing transaction
input = Input(Ed25519Fulfillment(public_key=user_pk),
[user_pk],
TransactionLink('somethingsomething', 0))
tx = Transaction.transfer([input], [([user_pk], 1)], Asset())
with pytest.raises(TransactionDoesNotExist):
tx.validate(Bigchain())
@ -557,16 +557,16 @@ class TestTransactionValidation(object):
def test_create_operation_with_inputs(self, b, user_pk, create_tx):
from bigchaindb.common.transaction import TransactionLink
# Manipulate fulfillment so that it has a `tx_input` defined even
# Manipulate input so that it has a `fulfills` defined even
# though it shouldn't have one
create_tx.fulfillments[0].tx_input = TransactionLink('abc', 0)
create_tx.inputs[0].fulfills = TransactionLink('abc', 0)
with pytest.raises(ValueError) as excinfo:
b.validate_transaction(create_tx)
assert excinfo.value.args[0] == 'A CREATE operation has no inputs'
def test_transfer_operation_no_inputs(self, b, user_pk,
signed_transfer_tx):
signed_transfer_tx.fulfillments[0].tx_input = None
signed_transfer_tx.inputs[0].fulfills = None
with pytest.raises(ValueError) as excinfo:
b.validate_transaction(signed_transfer_tx)
@ -577,7 +577,7 @@ class TestTransactionValidation(object):
from bigchaindb.common.exceptions import TransactionDoesNotExist
from bigchaindb.common.transaction import TransactionLink
signed_transfer_tx.fulfillments[0].tx_input = TransactionLink('c', 0)
signed_transfer_tx.inputs[0].fulfills = TransactionLink('c', 0)
with pytest.raises(TransactionDoesNotExist):
b.validate_transaction(signed_transfer_tx)
@ -593,7 +593,7 @@ class TestTransactionValidation(object):
tx = Transaction.create([pk], [([user_pk], 1)])
tx.operation = 'TRANSFER'
tx.asset = input_transaction.asset
tx.fulfillments[0].tx_input = input_tx
tx.inputs[0].fulfills = input_tx
with pytest.raises(InvalidSignature):
b.validate_transaction(tx)
@ -777,8 +777,8 @@ class TestMultipleInputs(object):
# validate transaction
assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1
assert len(tx.conditions) == 1
assert len(tx.inputs) == 1
assert len(tx.outputs) == 1
def test_single_owner_before_multiple_owners_after_single_input(self, b,
user_sk,
@ -798,8 +798,8 @@ class TestMultipleInputs(object):
tx = tx.sign([user_sk])
assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1
assert len(tx.conditions) == 1
assert len(tx.inputs) == 1
assert len(tx.outputs) == 1
@pytest.mark.usefixtures('inputs')
def test_multiple_owners_before_single_owner_after_single_input(self, b,
@ -830,8 +830,8 @@ class TestMultipleInputs(object):
# validate transaction
assert b.is_valid_transaction(transfer_tx) == transfer_tx
assert len(transfer_tx.fulfillments) == 1
assert len(transfer_tx.conditions) == 1
assert len(transfer_tx.inputs) == 1
assert len(transfer_tx.outputs) == 1
@pytest.mark.usefixtures('inputs')
def test_multiple_owners_before_multiple_owners_after_single_input(self, b,
@ -862,8 +862,8 @@ class TestMultipleInputs(object):
tx = tx.sign([user_sk, user2_sk])
assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1
assert len(tx.conditions) == 1
assert len(tx.inputs) == 1
assert len(tx.outputs) == 1
@pytest.mark.usefixtures('setup_database')
def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk):
@ -1025,8 +1025,8 @@ class TestMultipleInputs(object):
# check spents
input_txid = owned_inputs_user1.txid
input_cid = owned_inputs_user1.cid
spent_inputs_user1 = b.get_spent(input_txid, input_cid)
input_idx = owned_inputs_user1.idx
spent_inputs_user1 = b.get_spent(input_txid, input_idx)
assert spent_inputs_user1 is None
# create a transaction and block
@ -1035,7 +1035,7 @@ class TestMultipleInputs(object):
block = b.create_block([tx])
b.write_block(block)
spent_inputs_user1 = b.get_spent(input_txid, input_cid)
spent_inputs_user1 = b.get_spent(input_txid, input_idx)
assert spent_inputs_user1 == tx
@pytest.mark.usefixtures('setup_database')
@ -1061,8 +1061,8 @@ class TestMultipleInputs(object):
# check spents
input_txid = owned_inputs_user1.txid
input_cid = owned_inputs_user1.cid
spent_inputs_user1 = b.get_spent(input_txid, input_cid)
input_idx = owned_inputs_user1.idx
spent_inputs_user1 = b.get_spent(input_txid, input_idx)
assert spent_inputs_user1 is None
# create a transaction and block
@ -1076,7 +1076,7 @@ class TestMultipleInputs(object):
b.write_vote(vote)
# NOTE: I have no idea why this line is here
b.get_transaction(tx.id)
spent_inputs_user1 = b.get_spent(input_txid, input_cid)
spent_inputs_user1 = b.get_spent(input_txid, input_idx)
# Now there should be no spents (the block is invalid)
assert spent_inputs_user1 is None
@ -1105,7 +1105,7 @@ class TestMultipleInputs(object):
# check spents
for input_tx in owned_inputs_user1:
assert b.get_spent(input_tx.txid, input_tx.cid) is None
assert b.get_spent(input_tx.txid, input_tx.idx) is None
# transfer the first 2 inputs
tx_transfer = Transaction.transfer(tx_create.to_inputs()[:2],
@ -1117,12 +1117,12 @@ class TestMultipleInputs(object):
# check that used inputs are marked as spent
for ffill in tx_create.to_inputs()[:2]:
spent_tx = b.get_spent(ffill.tx_input.txid, ffill.tx_input.cid)
spent_tx = b.get_spent(ffill.fulfills.txid, ffill.fulfills.idx)
assert spent_tx == tx_transfer_signed
# check if remaining transaction that was unspent is also perceived
# spendable by BigchainDB
assert b.get_spent(tx_create.to_inputs()[2].tx_input.txid, 2) is None
assert b.get_spent(tx_create.to_inputs()[2].fulfills.txid, 2) is None
@pytest.mark.usefixtures('setup_database')
def test_get_spent_multiple_owners(self, b, user_sk, user_pk):
@ -1147,7 +1147,7 @@ class TestMultipleInputs(object):
# check spents
for input_tx in owned_inputs_user1:
assert b.get_spent(input_tx.txid, input_tx.cid) is None
assert b.get_spent(input_tx.txid, input_tx.idx) is None
# create a transaction
tx = Transaction.transfer(transactions[0].to_inputs(),

View File

@ -157,7 +157,7 @@ def test_vote_accumulates_transactions(b):
validation = vote_obj.validate_tx(tx, 123, 1)
assert validation == (True, 123, 1)
tx.fulfillments[0].fulfillment.signature = None
tx.inputs[0].fulfillment.signature = None
validation = vote_obj.validate_tx(tx, 456, 10)
assert validation == (False, 456, 10)

View File

@ -12,7 +12,7 @@ class TestTransactionModel(object):
tx.validate(b)
tx.operation = 'CREATE'
tx.fulfillments = []
tx.inputs = []
with raises(ValueError):
tx.validate(b)

View File

@ -35,8 +35,8 @@ def test_post_create_transaction_endpoint(b, client):
tx = tx.sign([user_priv])
res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict()))
assert res.json['fulfillments'][0]['owners_before'][0] == user_pub
assert res.json['conditions'][0]['owners_after'][0] == user_pub
assert res.json['inputs'][0]['owners_before'][0] == user_pub
assert res.json['outputs'][0]['public_keys'][0] == user_pub
def test_post_create_transaction_with_invalid_id(b, client):
@ -63,7 +63,7 @@ def test_post_create_transaction_with_invalid_signature(b, client):
tx = Transaction.create([user_pub], [([user_pub], 1)])
tx = tx.sign([user_priv]).to_dict()
tx['fulfillments'][0]['fulfillment'] = 'cf:0:0'
tx['inputs'][0]['fulfillment'] = 'cf:0:0'
res = client.post(TX_ENDPOINT, data=json.dumps(tx))
assert res.status_code == 400
@ -135,8 +135,8 @@ def test_post_transfer_transaction_endpoint(b, client, user_pk, user_sk):
res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict()))
assert res.json['fulfillments'][0]['owners_before'][0] == user_pk
assert res.json['conditions'][0]['owners_after'][0] == user_pub
assert res.json['inputs'][0]['owners_before'][0] == user_pk
assert res.json['outputs'][0]['public_keys'][0] == user_pub
@pytest.mark.usefixtures('inputs')