mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
s/fulfillments/inputs/g && s/conditions/outputs/g (code changes)
This commit is contained in:
parent
e2e3ecb9f4
commit
ed55b3984e
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
|
@ -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)
|
||||
|
||||
|
@ -12,7 +12,7 @@ class TestTransactionModel(object):
|
||||
tx.validate(b)
|
||||
|
||||
tx.operation = 'CREATE'
|
||||
tx.fulfillments = []
|
||||
tx.inputs = []
|
||||
with raises(ValueError):
|
||||
tx.validate(b)
|
||||
|
||||
|
@ -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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user