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

View File

@ -79,7 +79,7 @@ class CyclicBlockchainError(Exception):
class TransactionNotInValidBlock(Exception): class TransactionNotInValidBlock(Exception):
"""Raised when a transfer transaction is attempting to fulfill the """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): class AssetIdMismatch(Exception):

View File

@ -88,11 +88,10 @@ definitions:
Type of the transaction: Type of the transaction:
A ``CREATE`` transaction creates an asset in BigchainDB. This A ``CREATE`` transaction creates an asset in BigchainDB. This
transaction has outputs (conditions) but no inputs (fulfillments), transaction has outputs but no inputs, so a dummy fulfillment is used.
so a dummy fulfillment is used.
A ``TRANSFER`` transaction transfers ownership of an asset, by providing 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 A ``GENESIS`` transaction is a special case transaction used as the
sole member of the first block in a BigchainDB ledger. 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: if cursor:
return Asset.from_dict(cursor[0]['asset']) 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. """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 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: Args:
txid (str): The id of the transaction 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: Returns:
The transaction (Transaction) that used the `txid` as an input else The transaction (Transaction) that used the `txid` as an input else
`None` `None`
""" """
# checks if an input was already spent # checks if an input was already spent
# checks if the bigchain has any transaction with input {'txid': ..., 'cid': ...} # checks if the bigchain has any transaction with input {'txid': ...,
transactions = list(backend.query.get_spent(self.connection, txid, cid)) # 'idx': ...}
transactions = list(backend.query.get_spent(self.connection, txid, idx))
# a transaction_id should have been spent at most one time # a transaction_id should have been spent at most one time
if transactions: if transactions:
@ -404,7 +405,7 @@ class Bigchain(object):
owner (str): base58 encoded public key. owner (str): base58 encoded public key.
Returns: 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 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 # NOTE: It's OK to not serialize the transaction here, as we do not
# use it after the execution of this function. # 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 # 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 # for simple signature conditions there are no subfulfillments
# check if the owner is in the condition `owners_after` # check if the owner is in the condition `owners_after`
if len(cond['owners_after']) == 1: if len(out['public_keys']) == 1:
if cond['condition']['details']['public_key'] == owner: if out['condition']['details']['public_key'] == owner:
tx_link = TransactionLink(tx['id'], index) tx_link = TransactionLink(tx['id'], index)
else: 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 # in the condition. We need to iterate the subfulfillments to make sure there is a
# subfulfillment for `owner` # 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) tx_link = TransactionLink(tx['id'], index)
# check if input was already spent # 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) owned.append(tx_link)
return owned return owned

View File

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

View File

@ -57,9 +57,9 @@ Transaction Schema
* `Transaction`_ * `Transaction`_
* Condition_ * Input_
* Fulfillment_ * Output_
* Asset_ * Asset_
@ -71,15 +71,15 @@ Transaction
%(transaction)s %(transaction)s
Condition Input
---------- ----------
%(condition)s %(input)s
Fulfillment Output
----------- -----------
%(fulfillment)s %(output)s
Asset Asset
----- -----
@ -99,8 +99,8 @@ def generate_transaction_docs():
doc = TPL_TRANSACTION % { doc = TPL_TRANSACTION % {
'transaction': render_section('Transaction', schema), 'transaction': render_section('Transaction', schema),
'condition': render_section('Condition', defs['condition']), 'output': render_section('Output', defs['output']),
'fulfillment': render_section('Fulfillment', defs['fulfillment']), 'input': render_section('Input', defs['input']),
'asset': render_section('Asset', defs['asset']), 'asset': render_section('Asset', defs['asset']),
'metadata': render_section('Metadata', defs['metadata']['anyOf'][0]), 'metadata': render_section('Metadata', defs['metadata']['anyOf'][0]),
'container': 'transaction-schema', '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]) tx_signed = tx.sign([b.me_private])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.conditions) == 1 assert len(tx_signed.outputs) == 1
assert tx_signed.conditions[0].amount == 100 assert tx_signed.outputs[0].amount == 100
assert len(tx_signed.fulfillments) == 1 assert len(tx_signed.inputs) == 1
# CREATE divisible asset # 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]) tx_signed = tx.sign([b.me_private])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.conditions) == 2 assert len(tx_signed.outputs) == 2
assert tx_signed.conditions[0].amount == 50 assert tx_signed.outputs[0].amount == 50
assert tx_signed.conditions[1].amount == 50 assert tx_signed.outputs[1].amount == 50
assert len(tx_signed.fulfillments) == 1 assert len(tx_signed.inputs) == 1
# CREATE divisible asset # 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]) tx_signed = tx.sign([b.me_private])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.conditions) == 1 assert len(tx_signed.outputs) == 1
assert tx_signed.conditions[0].amount == 100 assert tx_signed.outputs[0].amount == 100
condition = tx_signed.conditions[0].to_dict() output = tx_signed.outputs[0].to_dict()
assert 'subfulfillments' in condition['condition']['details'] assert 'subfulfillments' in output['condition']['details']
assert len(condition['condition']['details']['subfulfillments']) == 2 assert len(output['condition']['details']['subfulfillments']) == 2
assert len(tx_signed.fulfillments) == 1 assert len(tx_signed.inputs) == 1
# CREATE divisible asset # 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]) tx_signed = tx.sign([b.me_private])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.conditions) == 2 assert len(tx_signed.outputs) == 2
assert tx_signed.conditions[0].amount == 50 assert tx_signed.outputs[0].amount == 50
assert tx_signed.conditions[1].amount == 50 assert tx_signed.outputs[1].amount == 50
condition_cid1 = tx_signed.conditions[1].to_dict() output_cid1 = tx_signed.outputs[1].to_dict()
assert 'subfulfillments' in condition_cid1['condition']['details'] assert 'subfulfillments' in output_cid1['condition']['details']
assert len(condition_cid1['condition']['details']['subfulfillments']) == 2 assert len(output_cid1['condition']['details']['subfulfillments']) == 2
assert len(tx_signed.fulfillments) == 1 assert len(tx_signed.inputs) == 1
# CREATE divisible asset # 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 = Transaction.create([b.me, user_pk], [([user_pk], 100)], asset=asset)
tx_signed = tx.sign([b.me_private, user_sk]) tx_signed = tx.sign([b.me_private, user_sk])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.conditions) == 1 assert len(tx_signed.outputs) == 1
assert tx_signed.conditions[0].amount == 100 assert tx_signed.outputs[0].amount == 100
assert len(tx_signed.fulfillments) == 1 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 'subfulfillments' in ffill
assert len(ffill['subfulfillments']) == 2 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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 1 assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset # 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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2 assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.conditions[0].amount == 50 assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50 assert tx_transfer_signed.outputs[1].amount == 50
assert len(tx_transfer_signed.fulfillments) == 1 assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset # 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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 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 'subfulfillments' in condition['condition']['details']
assert len(condition['condition']['details']['subfulfillments']) == 2 assert len(condition['condition']['details']['subfulfillments']) == 2
assert len(tx_transfer_signed.fulfillments) == 1 assert len(tx_transfer_signed.inputs) == 1
# TRANSFER divisible asset # 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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2 assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.conditions[0].amount == 50 assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50 assert tx_transfer_signed.outputs[1].amount == 50
condition_cid1 = tx_transfer_signed.conditions[1].to_dict() output_cid1 = tx_transfer_signed.outputs[1].to_dict()
assert 'subfulfillments' in condition_cid1['condition']['details'] assert 'subfulfillments' in output_cid1['condition']['details']
assert len(condition_cid1['condition']['details']['subfulfillments']) == 2 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 # 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]) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 1 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 'subfulfillments' in ffill
assert len(ffill['subfulfillments']) == 2 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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2 assert len(tx_transfer_signed.inputs) == 2
# TRANSFER divisible asset # 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]) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) assert tx_transfer_signed.validate(b)
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2 assert len(tx_transfer_signed.inputs) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict() ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict() ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' in ffill_fid0 assert 'subfulfillments' in ffill_fid0
assert 'subfulfillments' in ffill_fid1 assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid0['subfulfillments']) == 2 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]) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 100 assert tx_transfer_signed.outputs[0].amount == 100
assert len(tx_transfer_signed.fulfillments) == 2 assert len(tx_transfer_signed.inputs) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict() ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict() ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' not in ffill_fid0 assert 'subfulfillments' not in ffill_fid0
assert 'subfulfillments' in ffill_fid1 assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid1['subfulfillments']) == 2 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]) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 2 assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.conditions[0].amount == 50 assert tx_transfer_signed.outputs[0].amount == 50
assert tx_transfer_signed.conditions[1].amount == 50 assert tx_transfer_signed.outputs[1].amount == 50
assert len(tx_transfer_signed.fulfillments) == 2 assert len(tx_transfer_signed.inputs) == 2
cond_cid0 = tx_transfer_signed.conditions[0].to_dict() cond_cid0 = tx_transfer_signed.outputs[0].to_dict()
cond_cid1 = tx_transfer_signed.conditions[1].to_dict() cond_cid1 = tx_transfer_signed.outputs[1].to_dict()
assert 'subfulfillments' not in cond_cid0['condition']['details'] assert 'subfulfillments' not in cond_cid0['condition']['details']
assert 'subfulfillments' in cond_cid1['condition']['details'] assert 'subfulfillments' in cond_cid1['condition']['details']
assert len(cond_cid1['condition']['details']['subfulfillments']) == 2 assert len(cond_cid1['condition']['details']['subfulfillments']) == 2
ffill_fid0 = tx_transfer_signed.fulfillments[0].fulfillment.to_dict() ffill_fid0 = tx_transfer_signed.inputs[0].fulfillment.to_dict()
ffill_fid1 = tx_transfer_signed.fulfillments[1].fulfillment.to_dict() ffill_fid1 = tx_transfer_signed.inputs[1].fulfillment.to_dict()
assert 'subfulfillments' not in ffill_fid0 assert 'subfulfillments' not in ffill_fid0
assert 'subfulfillments' in ffill_fid1 assert 'subfulfillments' in ffill_fid1
assert len(ffill_fid1['subfulfillments']) == 2 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]) tx_transfer2_signed = tx_transfer2.sign([user_sk])
assert tx_transfer2_signed.validate(b) == tx_transfer2_signed assert tx_transfer2_signed.validate(b) == tx_transfer2_signed
assert len(tx_transfer2_signed.conditions) == 1 assert len(tx_transfer2_signed.outputs) == 1
assert tx_transfer2_signed.conditions[0].amount == 100 assert tx_transfer2_signed.outputs[0].amount == 100
assert len(tx_transfer2_signed.fulfillments) == 2 assert len(tx_transfer2_signed.inputs) == 2
fid0_input = tx_transfer2_signed.fulfillments[0].to_dict()['input']['txid'] fid0_input = tx_transfer2_signed.inputs[0].fulfills.txid
fid1_input = tx_transfer2_signed.fulfillments[1].to_dict()['input']['txid'] fid1_input = tx_transfer2_signed.inputs[1].fulfills.txid
assert fid0_input == tx_create.id assert fid0_input == tx_create.id
assert fid1_input == tx_transfer1.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]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 1 assert len(tx_transfer_signed.outputs) == 1
assert tx_transfer_signed.conditions[0].amount == 3 assert tx_transfer_signed.outputs[0].amount == 3
@pytest.mark.usefixtures('inputs') @pytest.mark.usefixtures('inputs')
@ -681,9 +681,9 @@ def test_divide(b, user_pk, user_sk):
tx_transfer_signed = tx_transfer.sign([user_sk]) tx_transfer_signed = tx_transfer.sign([user_sk])
assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.validate(b) == tx_transfer_signed
assert len(tx_transfer_signed.conditions) == 3 assert len(tx_transfer_signed.outputs) == 3
for condition in tx_transfer_signed.conditions: for output in tx_transfer_signed.outputs:
assert condition.amount == 1 assert output.amount == 1
# Check that negative inputs are caught when creating a TRANSFER transaction # 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(), tx_transfer = Transaction.transfer(tx_create.to_inputs(),
[([b.me], 4), ([b.me], 1)], [([b.me], 4), ([b.me], 1)],
asset=tx_create.asset) asset=tx_create.asset)
tx_transfer.conditions[1].amount = -1 tx_transfer.outputs[1].amount = -1
tx_transfer_signed = tx_transfer.sign([user_sk]) tx_transfer_signed = tx_transfer.sign([user_sk])
with pytest.raises(AmountError): with pytest.raises(AmountError):
@ -769,7 +769,7 @@ def test_non_positive_amounts_on_create_validate(b, user_pk):
asset = Asset(divisible=True) asset = Asset(divisible=True)
tx_create = Transaction.create([b.me], [([user_pk], 3)], tx_create = Transaction.create([b.me], [([user_pk], 3)],
asset=asset) asset=asset)
tx_create.conditions[0].amount = -3 tx_create.outputs[0].amount = -3
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx_create_signed = tx_create.sign([b.me_private]) tx_create_signed = tx_create.sign([b.me_private])

View File

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

View File

@ -2,111 +2,110 @@ from pytest import raises
from unittest.mock import patch from unittest.mock import patch
def test_fulfillment_serialization(ffill_uri, user_pub): def test_input_serialization(ffill_uri, user_pub):
from bigchaindb.common.transaction import Fulfillment from bigchaindb.common.transaction import Input
from cryptoconditions import Fulfillment as CCFulfillment from cryptoconditions import Fulfillment
expected = { expected = {
'owners_before': [user_pub], 'owners_before': [user_pub],
'fulfillment': ffill_uri, 'fulfillment': ffill_uri,
'input': None, 'fulfills': None,
} }
ffill = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub]) input = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
assert ffill.to_dict() == expected assert input.to_dict() == expected
def test_fulfillment_deserialization_with_uri(ffill_uri, user_pub): def test_input_deserialization_with_uri(ffill_uri, user_pub):
from bigchaindb.common.transaction import Fulfillment from bigchaindb.common.transaction import Input
from cryptoconditions import Fulfillment as CCFulfillment from cryptoconditions import Fulfillment
expected = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub]) expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
ffill = { ffill = {
'owners_before': [user_pub], 'owners_before': [user_pub],
'fulfillment': ffill_uri, '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): def test_input_deserialization_with_invalid_fulfillment(user_pub):
from bigchaindb.common.transaction import Fulfillment from bigchaindb.common.transaction import Input
ffill = { ffill = {
'owners_before': [user_pub], 'owners_before': [user_pub],
'fulfillment': None, 'fulfillment': None,
'input': None, 'fulfills': None,
} }
with raises(TypeError): 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.exceptions import InvalidSignature
from bigchaindb.common.transaction import Fulfillment from bigchaindb.common.transaction import Input
ffill = { ffill = {
'owners_before': [user_pub], 'owners_before': [user_pub],
'fulfillment': 'an invalid fulfillment', 'fulfillment': 'an invalid fulfillment',
'input': None, 'fulfills': None,
} }
with raises(InvalidSignature): with raises(InvalidSignature):
Fulfillment.from_dict(ffill) Input.from_dict(ffill)
def test_fulfillment_deserialization_with_unsigned_fulfillment(ffill_uri, def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub):
user_pub): from bigchaindb.common.transaction import Input
from bigchaindb.common.transaction import Fulfillment from cryptoconditions import Fulfillment
from cryptoconditions import Fulfillment as CCFulfillment
expected = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub]) expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
ffill = { ffill = {
'owners_before': [user_pub], 'owners_before': [user_pub],
'fulfillment': CCFulfillment.from_uri(ffill_uri), 'fulfillment': Fulfillment.from_uri(ffill_uri),
'input': None, '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): def test_condition_serialization(user_Ed25519, user_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
expected = { expected = {
'condition': { 'condition': {
'uri': user_Ed25519.condition_uri, 'uri': user_Ed25519.condition_uri,
'details': user_Ed25519.to_dict(), 'details': user_Ed25519.to_dict(),
}, },
'owners_after': [user_pub], 'public_keys': [user_pub],
'amount': 1, 'amount': 1,
} }
cond = Condition(user_Ed25519, [user_pub], 1) cond = Output(user_Ed25519, [user_pub], 1)
assert cond.to_dict() == expected assert cond.to_dict() == expected
def test_condition_deserialization(user_Ed25519, user_pub): 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 = { cond = {
'condition': { 'condition': {
'uri': user_Ed25519.condition_uri, 'uri': user_Ed25519.condition_uri,
'details': user_Ed25519.to_dict() 'details': user_Ed25519.to_dict()
}, },
'owners_after': [user_pub], 'public_keys': [user_pub],
'amount': 1, 'amount': 1,
} }
cond = Condition.from_dict(cond) cond = Output.from_dict(cond)
assert cond == expected assert cond == expected
def test_condition_hashlock_serialization(): def test_condition_hashlock_serialization():
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
from cryptoconditions import PreimageSha256Fulfillment from cryptoconditions import PreimageSha256Fulfillment
secret = b'wow much secret' secret = b'wow much secret'
@ -116,44 +115,44 @@ def test_condition_hashlock_serialization():
'condition': { 'condition': {
'uri': hashlock, 'uri': hashlock,
}, },
'owners_after': None, 'public_keys': None,
'amount': 1, 'amount': 1,
} }
cond = Condition(hashlock, amount=1) cond = Output(hashlock, amount=1)
assert cond.to_dict() == expected assert cond.to_dict() == expected
def test_condition_hashlock_deserialization(): def test_condition_hashlock_deserialization():
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
from cryptoconditions import PreimageSha256Fulfillment from cryptoconditions import PreimageSha256Fulfillment
secret = b'wow much secret' secret = b'wow much secret'
hashlock = PreimageSha256Fulfillment(preimage=secret).condition_uri hashlock = PreimageSha256Fulfillment(preimage=secret).condition_uri
expected = Condition(hashlock, amount=1) expected = Output(hashlock, amount=1)
cond = { cond = {
'condition': { 'condition': {
'uri': hashlock 'uri': hashlock
}, },
'owners_after': None, 'public_keys': None,
'amount': 1, 'amount': 1,
} }
cond = Condition.from_dict(cond) cond = Output.from_dict(cond)
assert cond == expected assert cond == expected
def test_invalid_condition_initialization(cond_uri, user_pub): def test_invalid_condition_initialization(cond_uri, user_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
with raises(TypeError): with raises(TypeError):
Condition(cond_uri, user_pub) Output(cond_uri, user_pub)
def test_generate_conditions_split_half_recursive(user_pub, user2_pub, def test_generate_conditions_split_half_recursive(user_pub, user2_pub,
user3_pub): user3_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub) 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_threshold.add_subfulfillment(expected_simple3)
expected.add_subfulfillment(expected_threshold) 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() assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_split_half_single_owner(user_pub, user2_pub, def test_generate_conditions_split_half_single_owner(user_pub, user2_pub,
user3_pub): user3_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub) 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_threshold)
expected.add_subfulfillment(expected_simple1) 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() assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_flat_ownage(user_pub, user2_pub, user3_pub): 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 from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
expected_simple1 = Ed25519Fulfillment(public_key=user_pub) 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_simple2)
expected.add_subfulfillment(expected_simple3) 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() assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_single_owner(user_pub): def test_generate_conditions_single_owner(user_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
from cryptoconditions import Ed25519Fulfillment from cryptoconditions import Ed25519Fulfillment
expected = Ed25519Fulfillment(public_key=user_pub) 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() assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_single_owner_with_condition(user_pub): 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 from cryptoconditions import Ed25519Fulfillment
expected = Ed25519Fulfillment(public_key=user_pub) expected = Ed25519Fulfillment(public_key=user_pub)
cond = Condition.generate([expected], 1) cond = Output.generate([expected], 1)
assert cond.fulfillment.to_dict() == expected.to_dict() assert cond.fulfillment.to_dict() == expected.to_dict()
def test_generate_conditions_invalid_parameters(user_pub, user2_pub, def test_generate_conditions_invalid_parameters(user_pub, user2_pub,
user3_pub): user3_pub):
from bigchaindb.common.transaction import Condition from bigchaindb.common.transaction import Output
with raises(ValueError): with raises(ValueError):
Condition.generate([], 1) Output.generate([], 1)
with raises(TypeError): with raises(TypeError):
Condition.generate('not a list', 1) Output.generate('not a list', 1)
with raises(ValueError): with raises(ValueError):
Condition.generate([[user_pub, [user2_pub, [user3_pub]]]], 1) Output.generate([[user_pub, [user2_pub, [user3_pub]]]], 1)
with raises(ValueError): with raises(ValueError):
Condition.generate([[user_pub]], 1) Output.generate([[user_pub]], 1)
def test_invalid_transaction_initialization(): def test_invalid_transaction_initialization():
@ -253,21 +252,21 @@ def test_invalid_transaction_initialization():
Transaction( Transaction(
operation='CREATE', operation='CREATE',
asset=Asset(), asset=Asset(),
conditions='invalid conditions' outputs='invalid outputs'
) )
with raises(TypeError): with raises(TypeError):
Transaction( Transaction(
operation='CREATE', operation='CREATE',
asset=Asset(), asset=Asset(),
conditions=[], outputs=[],
fulfillments='invalid fulfillments' inputs='invalid inputs'
) )
with raises(TypeError): with raises(TypeError):
Transaction( Transaction(
operation='CREATE', operation='CREATE',
asset=Asset(), asset=Asset(),
conditions=[], outputs=[],
fulfillments=[], inputs=[],
metadata='invalid metadata' metadata='invalid metadata'
) )
@ -291,7 +290,7 @@ def test_create_default_asset_on_tx_initialization():
validate_transaction_model(tx) 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.transaction import Transaction, Asset
from bigchaindb.common.exceptions import ValidationError from bigchaindb.common.exceptions import ValidationError
from .util import validate_transaction_model from .util import validate_transaction_model
@ -301,10 +300,10 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
expected = { expected = {
'id': tx_id, 'id': tx_id,
'version': Transaction.VERSION, 'version': Transaction.VERSION,
# NOTE: This test assumes that Fulfillments and Conditions can # NOTE: This test assumes that Inputs and Outputs can
# successfully be serialized # successfully be serialized
'fulfillments': [user_ffill.to_dict()], 'inputs': [user_input.to_dict()],
'conditions': [user_cond.to_dict()], 'outputs': [user_output.to_dict()],
'operation': Transaction.CREATE, 'operation': Transaction.CREATE,
'metadata': None, 'metadata': None,
'asset': { '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], tx = Transaction(Transaction.CREATE, Asset(data, data_id), [user_input],
[user_cond]) [user_output])
tx_dict = tx.to_dict() tx_dict = tx.to_dict()
tx_dict['id'] = tx_id tx_dict['id'] = tx_id
tx_dict['asset']['id'] = data_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) 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 bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model from .util import validate_transaction_model
expected_asset = Asset(data, uuid4) expected_asset = Asset(data, uuid4)
expected = Transaction(Transaction.CREATE, expected_asset, [user_ffill], expected = Transaction(Transaction.CREATE, expected_asset, [user_input],
[user_cond], None, Transaction.VERSION) [user_output], None, Transaction.VERSION)
tx = { tx = {
'version': Transaction.VERSION, 'version': Transaction.VERSION,
# NOTE: This test assumes that Fulfillments and Conditions can # NOTE: This test assumes that Inputs and Outputs can
# successfully be serialized # successfully be serialized
'fulfillments': [user_ffill.to_dict()], 'inputs': [user_input.to_dict()],
'conditions': [user_cond.to_dict()], 'outputs': [user_output.to_dict()],
'operation': Transaction.CREATE, 'operation': Transaction.CREATE,
'metadata': None, 'metadata': None,
'asset': { 'asset': {
@ -374,13 +372,11 @@ def test_tx_serialization_with_incorrect_hash(utx):
utx_dict.pop('id') utx_dict.pop('id')
def test_invalid_fulfillment_initialization(user_ffill, user_pub): def test_invalid_fulfillment_initialization(user_input, user_pub):
from bigchaindb.common.transaction import Fulfillment from bigchaindb.common.transaction import Input
with raises(TypeError): with raises(TypeError):
Fulfillment(user_ffill, user_pub) Input(user_input, tx_input='somethingthatiswrong')
with raises(TypeError):
Fulfillment(user_ffill, [], tx_input='somethingthatiswrong')
def test_transaction_link_serialization(): def test_transaction_link_serialization():
@ -389,7 +385,7 @@ def test_transaction_link_serialization():
tx_id = 'a transaction id' tx_id = 'a transaction id'
expected = { expected = {
'txid': tx_id, 'txid': tx_id,
'cid': 0, 'idx': 0,
} }
tx_link = TransactionLink(tx_id, 0) tx_link = TransactionLink(tx_id, 0)
@ -412,7 +408,7 @@ def test_transaction_link_deserialization():
expected = TransactionLink(tx_id, 0) expected = TransactionLink(tx_id, 0)
tx_link = { tx_link = {
'txid': tx_id, 'txid': tx_id,
'cid': 0, 'idx': 0,
} }
tx_link = TransactionLink.from_dict(tx_link) 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) 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 from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset(), [], []) 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 from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset()) tx = Transaction(Transaction.CREATE, Asset())
with raises(TypeError): 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 bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model from .util import validate_transaction_model
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset()) 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) 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 from bigchaindb.common.transaction import Transaction, Asset
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, Asset(), [], []) tx = Transaction(Transaction.CREATE, Asset(), [], [])
with raises(TypeError): with raises(TypeError):
tx.add_condition('somewronginput') tx.add_output('somewronginput')
def test_sign_with_invalid_parameters(utx, user_priv): 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) 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 copy import deepcopy
from bigchaindb.common.crypto import PrivateKey from bigchaindb.common.crypto import PrivateKey
from bigchaindb.common.transaction import Transaction, Asset from bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(), [user_ffill], [user_cond]) tx = Transaction(Transaction.CREATE, Asset(), [user_input], [user_output])
expected = deepcopy(user_cond) expected = deepcopy(user_output)
expected.fulfillment.sign(str(tx).encode(), PrivateKey(user_priv)) expected.fulfillment.sign(str(tx).encode(), PrivateKey(user_priv))
tx.sign([user_priv]) tx.sign([user_priv])
assert tx.fulfillments[0].to_dict()['fulfillment'] == \ assert tx.inputs[0].to_dict()['fulfillment'] == \
expected.fulfillment.serialize_uri() expected.fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True assert tx.inputs_valid() is True
validate_transaction_model(tx) validate_transaction_model(tx)
def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, def test_invoke_simple_signature_fulfillment_with_invalid_params(utx,
user_ffill): user_input):
from bigchaindb.common.exceptions import KeypairMismatchException from bigchaindb.common.exceptions import KeypairMismatchException
with raises(KeypairMismatchException): with raises(KeypairMismatchException):
invalid_key_pair = {'wrong_pub_key': 'wrong_priv_key'} invalid_key_pair = {'wrong_pub_key': 'wrong_priv_key'}
utx._sign_simple_signature_fulfillment(user_ffill, utx._sign_simple_signature_fulfillment(user_input,
0, 0,
'somemessage', 'somemessage',
invalid_key_pair) 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): user3_pub, user3_priv):
from bigchaindb.common.exceptions import KeypairMismatchException from bigchaindb.common.exceptions import KeypairMismatchException
with raises(KeypairMismatchException): with raises(KeypairMismatchException):
utx._sign_threshold_signature_fulfillment(user_user2_threshold_ffill, utx._sign_threshold_signature_fulfillment(user_user2_threshold_input,
0, 0,
'somemessage', 'somemessage',
{user3_pub: user3_priv}) {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): def test_validate_fulfillment_with_invalid_parameters(utx):
from bigchaindb.common.transaction import Transaction from bigchaindb.common.transaction import Transaction
input_conditions = [cond.fulfillment.condition_uri for cond input_conditions = [out.fulfillment.condition_uri for out in utx.outputs]
in utx.conditions]
tx_dict = utx.to_dict() tx_dict = utx.to_dict()
tx_dict = Transaction._remove_signatures(tx_dict) tx_dict = Transaction._remove_signatures(tx_dict)
tx_serialized = Transaction._to_str(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, tx_serialized,
input_conditions) is False 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 copy import deepcopy
from bigchaindb.common.crypto import PrivateKey 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 from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(divisible=True), tx = Transaction(Transaction.CREATE, Asset(divisible=True),
[user_ffill, deepcopy(user_ffill)], [user_input, deepcopy(user_input)],
[user_cond, deepcopy(user_cond)]) [user_output, deepcopy(user_output)])
expected_first = deepcopy(tx) expected_first = deepcopy(tx)
expected_second = deepcopy(tx) expected_second = deepcopy(tx)
expected_first.fulfillments = [expected_first.fulfillments[0]] expected_first.inputs = [expected_first.inputs[0]]
expected_second.fulfillments = [expected_second.fulfillments[1]] expected_second.inputs = [expected_second.inputs[1]]
expected_first_bytes = str(expected_first).encode() 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)) PrivateKey(user_priv))
expected_second_bytes = str(expected_second).encode() expected_second_bytes = str(expected_second).encode()
expected_second.fulfillments[0].fulfillment.sign(expected_second_bytes, expected_second.inputs[0].fulfillment.sign(expected_second_bytes,
PrivateKey(user_priv)) PrivateKey(user_priv))
tx.sign([user_priv]) tx.sign([user_priv])
assert tx.fulfillments[0].to_dict()['fulfillment'] == \ assert tx.inputs[0].to_dict()['fulfillment'] == \
expected_first.fulfillments[0].fulfillment.serialize_uri() expected_first.inputs[0].fulfillment.serialize_uri()
assert tx.fulfillments[1].to_dict()['fulfillment'] == \ assert tx.inputs[1].to_dict()['fulfillment'] == \
expected_second.fulfillments[0].fulfillment.serialize_uri() expected_second.inputs[0].fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True assert tx.inputs_valid() is True
validate_transaction_model(tx) validate_transaction_model(tx)
def test_validate_tx_threshold_create_signature(user_user2_threshold_ffill, def test_validate_tx_threshold_create_signature(user_user2_threshold_input,
user_user2_threshold_cond, user_user2_threshold_output,
user_pub, user_pub,
user2_pub, user2_pub,
user_priv, 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 bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(), [user_user2_threshold_ffill], tx = Transaction(Transaction.CREATE, Asset(), [user_user2_threshold_input],
[user_user2_threshold_cond]) [user_user2_threshold_output])
expected = deepcopy(user_user2_threshold_cond) expected = deepcopy(user_user2_threshold_output)
expected.fulfillment.subconditions[0]['body'].sign(str(tx).encode(), expected.fulfillment.subconditions[0]['body'].sign(str(tx).encode(),
PrivateKey(user_priv)) PrivateKey(user_priv))
expected.fulfillment.subconditions[1]['body'].sign(str(tx).encode(), expected.fulfillment.subconditions[1]['body'].sign(str(tx).encode(),
PrivateKey(user2_priv)) PrivateKey(user2_priv))
tx.sign([user_priv, 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() expected.fulfillment.serialize_uri()
assert tx.fulfillments_valid() is True assert tx.inputs_valid() is True
validate_transaction_model(tx) validate_transaction_model(tx)
def test_multiple_fulfillment_validation_of_transfer_tx(user_ffill, user_cond, def test_multiple_input_validation_of_transfer_tx(user_input, user_output,
user_priv, user2_pub, user_priv, user2_pub,
user2_priv, user3_pub, user2_priv, user3_pub,
user3_priv): user3_priv):
from copy import deepcopy from copy import deepcopy
from bigchaindb.common.transaction import (Transaction, TransactionLink, from bigchaindb.common.transaction import (Transaction, TransactionLink,
Fulfillment, Condition, Asset) Input, Output, Asset)
from cryptoconditions import Ed25519Fulfillment from cryptoconditions import Ed25519Fulfillment
from .util import validate_transaction_model from .util import validate_transaction_model
tx = Transaction(Transaction.CREATE, Asset(divisible=True), tx = Transaction(Transaction.CREATE, Asset(divisible=True),
[user_ffill, deepcopy(user_ffill)], [user_input, deepcopy(user_input)],
[user_cond, deepcopy(user_cond)]) [user_output, deepcopy(user_output)])
tx.sign([user_priv]) tx.sign([user_priv])
fulfillments = [Fulfillment(cond.fulfillment, cond.owners_after, inputs = [Input(cond.fulfillment, cond.public_keys,
TransactionLink(tx.id, index)) TransactionLink(tx.id, index))
for index, cond in enumerate(tx.conditions)] for index, cond in enumerate(tx.outputs)]
conditions = [Condition(Ed25519Fulfillment(public_key=user3_pub), outputs = [Output(Ed25519Fulfillment(public_key=user3_pub), [user3_pub]),
[user3_pub]), Output(Ed25519Fulfillment(public_key=user3_pub), [user3_pub])]
Condition(Ed25519Fulfillment(public_key=user3_pub), transfer_tx = Transaction('TRANSFER', tx.asset, inputs, outputs)
[user3_pub])]
transfer_tx = Transaction('TRANSFER', tx.asset, fulfillments, conditions)
transfer_tx = transfer_tx.sign([user_priv]) 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) validate_transaction_model(tx)
def test_validate_fulfillments_of_transfer_tx_with_invalid_params(transfer_tx, def test_validate_inputs_of_transfer_tx_with_invalid_params(
cond_uri, transfer_tx, cond_uri, utx, user2_pub, user_priv):
utx, from bigchaindb.common.transaction import Output
user2_pub,
user_priv):
from bigchaindb.common.transaction import Condition
from cryptoconditions import Ed25519Fulfillment from cryptoconditions import Ed25519Fulfillment
invalid_cond = Condition(Ed25519Fulfillment.from_uri('cf:0:'), ['invalid']) invalid_out = Output(Ed25519Fulfillment.from_uri('cf:0:'), ['invalid'])
assert transfer_tx.fulfillments_valid([invalid_cond]) is False assert transfer_tx.inputs_valid([invalid_out]) is False
invalid_cond = utx.conditions[0] invalid_out = utx.outputs[0]
invalid_cond.owners_after = 'invalid' invalid_out.public_key = 'invalid'
assert transfer_tx.fulfillments_valid([invalid_cond]) is True assert transfer_tx.inputs_valid([invalid_out]) is True
with raises(TypeError): with raises(TypeError):
assert transfer_tx.fulfillments_valid(None) is False assert transfer_tx.inputs_valid(None) is False
with raises(AttributeError): with raises(AttributeError):
transfer_tx.fulfillments_valid('not a list') transfer_tx.inputs_valid('not a list')
with raises(ValueError): with raises(ValueError):
transfer_tx.fulfillments_valid([]) transfer_tx.inputs_valid([])
with raises(TypeError): with raises(TypeError):
transfer_tx.operation = "Operation that doesn't exist" 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 bigchaindb.common.transaction import Transaction, Asset
from .util import validate_transaction_model from .util import validate_transaction_model
expected = { expected = {
'conditions': [user_cond.to_dict()], 'outputs': [user_output.to_dict()],
'metadata': data, 'metadata': data,
'asset': { 'asset': {
'id': uuid4, 'id': uuid4,
@ -755,13 +739,13 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
'refillable': False, 'refillable': False,
'data': data, 'data': data,
}, },
'fulfillments': [ 'inputs': [
{ {
'owners_before': [ 'owners_before': [
user_pub user_pub
], ],
'fulfillment': None, 'fulfillment': None,
'input': None 'fulfills': None
} }
], ],
'operation': 'CREATE', 'operation': 'CREATE',
@ -771,7 +755,7 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
asset = Asset(data, uuid4) asset = Asset(data, uuid4)
tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset) tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset)
tx_dict = tx.to_dict() tx_dict = tx.to_dict()
tx_dict['fulfillments'][0]['fulfillment'] = None tx_dict['inputs'][0]['fulfillment'] = None
tx_dict.pop('id') tx_dict.pop('id')
assert tx_dict == expected 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 = Transaction.create([user_pub], [([user_pub], 1)], data, Asset())
tx = tx.sign([user_priv]) 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): 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` # a fulfillment for a create transaction with multiple `owners_before`
# is a fulfillment for an implicit threshold condition with # is a fulfillment for an implicit threshold condition with
# weight = len(owners_before) # weight = len(owners_before)
ffill = Fulfillment.generate([user_pub, user2_pub]).to_dict() input = Input.generate([user_pub, user2_pub]).to_dict()
expected = { expected = {
'conditions': [user_cond.to_dict(), user2_cond.to_dict()], 'outputs': [user_output.to_dict(), user2_output.to_dict()],
'metadata': { 'metadata': {
'message': 'hello' 'message': 'hello'
}, },
'fulfillments': [ffill], 'inputs': [input],
'operation': 'CREATE', 'operation': 'CREATE',
'version': 1 'version': 1
} }
@ -825,19 +809,19 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv,
metadata={'message': 'hello'}, metadata={'message': 'hello'},
asset=Asset(divisible=True)) asset=Asset(divisible=True))
tx = tx.sign([user_priv, user2_priv]) tx = tx.sign([user_priv, user2_priv])
assert tx.fulfillments_valid() is True assert tx.inputs_valid() is True
validate_transaction_model(tx) validate_transaction_model(tx)
def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
user_user2_threshold_cond, user_user2_threshold_output,
user_user2_threshold_ffill, data, user_user2_threshold_input, data,
uuid4): uuid4):
from bigchaindb.common.transaction import Transaction, Asset from bigchaindb.common.transaction import Transaction, Asset
expected = { expected = {
'conditions': [user_user2_threshold_cond.to_dict()], 'outputs': [user_user2_threshold_output.to_dict()],
'metadata': data, 'metadata': data,
'asset': { 'asset': {
'id': uuid4, 'id': uuid4,
@ -846,13 +830,13 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
'refillable': False, 'refillable': False,
'data': data, 'data': data,
}, },
'fulfillments': [ 'inputs': [
{ {
'owners_before': [ 'owners_before': [
user_pub, user_pub
], ],
'fulfillment': None, 'fulfillment': None,
'input': None 'fulfills': None
}, },
], ],
'operation': 'CREATE', 'operation': 'CREATE',
@ -863,7 +847,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
data, asset) data, asset)
tx_dict = tx.to_dict() tx_dict = tx.to_dict()
tx_dict.pop('id') tx_dict.pop('id')
tx_dict['fulfillments'][0]['fulfillment'] = None tx_dict['inputs'][0]['fulfillment'] = None
assert tx_dict == expected 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)], tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)],
data, Asset()) data, Asset())
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
assert tx.fulfillments_valid() is True assert tx.inputs_valid() is True
validate_transaction_model(tx) validate_transaction_model(tx)
@ -898,18 +882,18 @@ def test_create_create_transaction_with_invalid_parameters(user_pub):
Transaction.create([user_pub], [([user_pub],)]) Transaction.create([user_pub], [([user_pub],)])
def test_conditions_to_inputs(tx): def test_outputs_to_inputs(tx):
ffills = tx.to_inputs([0]) inputs = tx.to_inputs([0])
assert len(ffills) == 1 assert len(inputs) == 1
ffill = ffills.pop() input = inputs.pop()
assert ffill.fulfillment == tx.conditions[0].fulfillment assert input.owners_before == tx.outputs[0].public_keys
assert ffill.owners_before == tx.conditions[0].owners_after assert input.fulfillment == tx.outputs[0].fulfillment
assert ffill.tx_input.txid == tx.id assert input.fulfills.txid == tx.id
assert ffill.tx_input.cid == 0 assert input.fulfills.idx == 0
def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, 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 copy import deepcopy
from bigchaindb.common.crypto import PrivateKey from bigchaindb.common.crypto import PrivateKey
from bigchaindb.common.transaction import Transaction, Asset 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 from .util import validate_transaction_model
expected = { expected = {
'conditions': [user2_cond.to_dict()], 'outputs': [user2_output.to_dict()],
'metadata': None, 'metadata': None,
'asset': { 'asset': {
'id': uuid4, 'id': uuid4,
}, },
'fulfillments': [ 'inputs': [
{ {
'owners_before': [ 'owners_before': [
user_pub user_pub
], ],
'fulfillment': None, 'fulfillment': None,
'input': { 'fulfills': {
'txid': tx.id, '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(), expected_input.fulfillment.sign(serialize(expected).encode(),
PrivateKey(user_priv)) PrivateKey(user_priv))
expected_ffill = expected_input.fulfillment.serialize_uri() 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 assert transfer_ffill == expected_ffill
transfer_tx = Transaction.from_dict(transfer_tx) 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) validate_transaction_model(transfer_tx)
def test_create_transfer_transaction_multiple_io(user_pub, user_priv, def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
user2_pub, user2_priv, user2_pub, user2_priv,
user3_pub, user2_cond): user3_pub, user2_output):
from bigchaindb.common.transaction import Transaction, Asset from bigchaindb.common.transaction import Transaction, Asset
asset = Asset(divisible=True) asset = Asset(divisible=True)
@ -969,26 +953,26 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
expected = { expected = {
'conditions': [user2_cond.to_dict(), user2_cond.to_dict()], 'outputs': [user2_output.to_dict(), user2_output.to_dict()],
'metadata': None, 'metadata': None,
'fulfillments': [ 'inputs': [
{ {
'owners_before': [ 'owners_before': [
user_pub user_pub
], ],
'fulfillment': None, 'fulfillment': None,
'input': { 'fulfills': {
'txid': tx.id, 'txid': tx.id,
'cid': 0 'idx': 0
} }
}, { }, {
'owners_before': [ 'owners_before': [
user2_pub user2_pub
], ],
'fulfillment': None, 'fulfillment': None,
'input': { 'fulfills': {
'txid': tx.id, '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) asset=tx.asset)
transfer_tx = transfer_tx.sign([user_priv, user2_priv]) transfer_tx = transfer_tx.sign([user_priv, user2_priv])
assert len(transfer_tx.fulfillments) == 2 assert len(transfer_tx.inputs) == 2
assert len(transfer_tx.conditions) == 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 = transfer_tx.to_dict()
transfer_tx['fulfillments'][0]['fulfillment'] = None transfer_tx['inputs'][0]['fulfillment'] = None
transfer_tx['fulfillments'][1]['fulfillment'] = None transfer_tx['inputs'][1]['fulfillment'] = None
transfer_tx.pop('asset') transfer_tx.pop('asset')
transfer_tx.pop('id') transfer_tx.pop('id')
@ -1038,7 +1022,7 @@ def test_cant_add_empty_condition():
with patch.object(Asset, 'validate_asset', return_value=None): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, None) tx = Transaction(Transaction.CREATE, None)
with raises(TypeError): with raises(TypeError):
tx.add_condition(None) tx.add_output(None)
def test_cant_add_empty_fulfillment(): 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): with patch.object(Asset, 'validate_asset', return_value=None):
tx = Transaction(Transaction.CREATE, None) tx = Transaction(Transaction.CREATE, None)
with raises(TypeError): 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 len(block['block']['transactions']) == 1
assert block['block']['transactions'][0]['operation'] == 'GENESIS' 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): def test_create_genesis_block_fails_if_table_not_empty(self, b):
from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError
@ -527,16 +527,16 @@ class TestBigchainApi(object):
def test_non_create_input_not_found(self, b, user_pk): def test_non_create_input_not_found(self, b, user_pk):
from cryptoconditions import Ed25519Fulfillment from cryptoconditions import Ed25519Fulfillment
from bigchaindb.common.exceptions import TransactionDoesNotExist from bigchaindb.common.exceptions import TransactionDoesNotExist
from bigchaindb.common.transaction import (Fulfillment, Asset, from bigchaindb.common.transaction import (Input, Asset,
TransactionLink) TransactionLink)
from bigchaindb.models import Transaction from bigchaindb.models import Transaction
from bigchaindb import Bigchain from bigchaindb import Bigchain
# Create a fulfillment for a non existing transaction # Create an input for a non existing transaction
fulfillment = Fulfillment(Ed25519Fulfillment(public_key=user_pk), input = Input(Ed25519Fulfillment(public_key=user_pk),
[user_pk], [user_pk],
TransactionLink('somethingsomething', 0)) TransactionLink('somethingsomething', 0))
tx = Transaction.transfer([fulfillment], [([user_pk], 1)], Asset()) tx = Transaction.transfer([input], [([user_pk], 1)], Asset())
with pytest.raises(TransactionDoesNotExist): with pytest.raises(TransactionDoesNotExist):
tx.validate(Bigchain()) tx.validate(Bigchain())
@ -557,16 +557,16 @@ class TestTransactionValidation(object):
def test_create_operation_with_inputs(self, b, user_pk, create_tx): def test_create_operation_with_inputs(self, b, user_pk, create_tx):
from bigchaindb.common.transaction import TransactionLink 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 # 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: with pytest.raises(ValueError) as excinfo:
b.validate_transaction(create_tx) b.validate_transaction(create_tx)
assert excinfo.value.args[0] == 'A CREATE operation has no inputs' assert excinfo.value.args[0] == 'A CREATE operation has no inputs'
def test_transfer_operation_no_inputs(self, b, user_pk, def test_transfer_operation_no_inputs(self, b, user_pk,
signed_transfer_tx): signed_transfer_tx):
signed_transfer_tx.fulfillments[0].tx_input = None signed_transfer_tx.inputs[0].fulfills = None
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
b.validate_transaction(signed_transfer_tx) b.validate_transaction(signed_transfer_tx)
@ -577,7 +577,7 @@ class TestTransactionValidation(object):
from bigchaindb.common.exceptions import TransactionDoesNotExist from bigchaindb.common.exceptions import TransactionDoesNotExist
from bigchaindb.common.transaction import TransactionLink 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): with pytest.raises(TransactionDoesNotExist):
b.validate_transaction(signed_transfer_tx) b.validate_transaction(signed_transfer_tx)
@ -593,7 +593,7 @@ class TestTransactionValidation(object):
tx = Transaction.create([pk], [([user_pk], 1)]) tx = Transaction.create([pk], [([user_pk], 1)])
tx.operation = 'TRANSFER' tx.operation = 'TRANSFER'
tx.asset = input_transaction.asset tx.asset = input_transaction.asset
tx.fulfillments[0].tx_input = input_tx tx.inputs[0].fulfills = input_tx
with pytest.raises(InvalidSignature): with pytest.raises(InvalidSignature):
b.validate_transaction(tx) b.validate_transaction(tx)
@ -777,8 +777,8 @@ class TestMultipleInputs(object):
# validate transaction # validate transaction
assert b.is_valid_transaction(tx) == tx assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1 assert len(tx.inputs) == 1
assert len(tx.conditions) == 1 assert len(tx.outputs) == 1
def test_single_owner_before_multiple_owners_after_single_input(self, b, def test_single_owner_before_multiple_owners_after_single_input(self, b,
user_sk, user_sk,
@ -798,8 +798,8 @@ class TestMultipleInputs(object):
tx = tx.sign([user_sk]) tx = tx.sign([user_sk])
assert b.is_valid_transaction(tx) == tx assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1 assert len(tx.inputs) == 1
assert len(tx.conditions) == 1 assert len(tx.outputs) == 1
@pytest.mark.usefixtures('inputs') @pytest.mark.usefixtures('inputs')
def test_multiple_owners_before_single_owner_after_single_input(self, b, def test_multiple_owners_before_single_owner_after_single_input(self, b,
@ -830,8 +830,8 @@ class TestMultipleInputs(object):
# validate transaction # validate transaction
assert b.is_valid_transaction(transfer_tx) == transfer_tx assert b.is_valid_transaction(transfer_tx) == transfer_tx
assert len(transfer_tx.fulfillments) == 1 assert len(transfer_tx.inputs) == 1
assert len(transfer_tx.conditions) == 1 assert len(transfer_tx.outputs) == 1
@pytest.mark.usefixtures('inputs') @pytest.mark.usefixtures('inputs')
def test_multiple_owners_before_multiple_owners_after_single_input(self, b, 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]) tx = tx.sign([user_sk, user2_sk])
assert b.is_valid_transaction(tx) == tx assert b.is_valid_transaction(tx) == tx
assert len(tx.fulfillments) == 1 assert len(tx.inputs) == 1
assert len(tx.conditions) == 1 assert len(tx.outputs) == 1
@pytest.mark.usefixtures('setup_database') @pytest.mark.usefixtures('setup_database')
def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk): def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk):
@ -1025,8 +1025,8 @@ class TestMultipleInputs(object):
# check spents # check spents
input_txid = owned_inputs_user1.txid input_txid = owned_inputs_user1.txid
input_cid = owned_inputs_user1.cid input_idx = owned_inputs_user1.idx
spent_inputs_user1 = b.get_spent(input_txid, input_cid) spent_inputs_user1 = b.get_spent(input_txid, input_idx)
assert spent_inputs_user1 is None assert spent_inputs_user1 is None
# create a transaction and block # create a transaction and block
@ -1035,7 +1035,7 @@ class TestMultipleInputs(object):
block = b.create_block([tx]) block = b.create_block([tx])
b.write_block(block) 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 assert spent_inputs_user1 == tx
@pytest.mark.usefixtures('setup_database') @pytest.mark.usefixtures('setup_database')
@ -1061,8 +1061,8 @@ class TestMultipleInputs(object):
# check spents # check spents
input_txid = owned_inputs_user1.txid input_txid = owned_inputs_user1.txid
input_cid = owned_inputs_user1.cid input_idx = owned_inputs_user1.idx
spent_inputs_user1 = b.get_spent(input_txid, input_cid) spent_inputs_user1 = b.get_spent(input_txid, input_idx)
assert spent_inputs_user1 is None assert spent_inputs_user1 is None
# create a transaction and block # create a transaction and block
@ -1076,7 +1076,7 @@ class TestMultipleInputs(object):
b.write_vote(vote) b.write_vote(vote)
# NOTE: I have no idea why this line is here # NOTE: I have no idea why this line is here
b.get_transaction(tx.id) 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) # Now there should be no spents (the block is invalid)
assert spent_inputs_user1 is None assert spent_inputs_user1 is None
@ -1105,7 +1105,7 @@ class TestMultipleInputs(object):
# check spents # check spents
for input_tx in owned_inputs_user1: 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 # transfer the first 2 inputs
tx_transfer = Transaction.transfer(tx_create.to_inputs()[:2], tx_transfer = Transaction.transfer(tx_create.to_inputs()[:2],
@ -1117,12 +1117,12 @@ class TestMultipleInputs(object):
# check that used inputs are marked as spent # check that used inputs are marked as spent
for ffill in tx_create.to_inputs()[:2]: 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 assert spent_tx == tx_transfer_signed
# check if remaining transaction that was unspent is also perceived # check if remaining transaction that was unspent is also perceived
# spendable by BigchainDB # 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') @pytest.mark.usefixtures('setup_database')
def test_get_spent_multiple_owners(self, b, user_sk, user_pk): def test_get_spent_multiple_owners(self, b, user_sk, user_pk):
@ -1147,7 +1147,7 @@ class TestMultipleInputs(object):
# check spents # check spents
for input_tx in owned_inputs_user1: 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 # create a transaction
tx = Transaction.transfer(transactions[0].to_inputs(), 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) validation = vote_obj.validate_tx(tx, 123, 1)
assert validation == (True, 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) validation = vote_obj.validate_tx(tx, 456, 10)
assert validation == (False, 456, 10) assert validation == (False, 456, 10)

View File

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

View File

@ -35,8 +35,8 @@ def test_post_create_transaction_endpoint(b, client):
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict()))
assert res.json['fulfillments'][0]['owners_before'][0] == user_pub assert res.json['inputs'][0]['owners_before'][0] == user_pub
assert res.json['conditions'][0]['owners_after'][0] == user_pub assert res.json['outputs'][0]['public_keys'][0] == user_pub
def test_post_create_transaction_with_invalid_id(b, client): 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 = Transaction.create([user_pub], [([user_pub], 1)])
tx = tx.sign([user_priv]).to_dict() 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)) res = client.post(TX_ENDPOINT, data=json.dumps(tx))
assert res.status_code == 400 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())) 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['inputs'][0]['owners_before'][0] == user_pk
assert res.json['conditions'][0]['owners_after'][0] == user_pub assert res.json['outputs'][0]['public_keys'][0] == user_pub
@pytest.mark.usefixtures('inputs') @pytest.mark.usefixtures('inputs')