mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
duplicate tx.id into tx.asset.id in CREATE transactions
This commit is contained in:
parent
e08bf52fa7
commit
003519b0a8
@ -85,22 +85,6 @@ def get_blocks_status_from_transaction(conn, transaction_id):
|
|||||||
|
|
||||||
@register_query(MongoDBConnection)
|
@register_query(MongoDBConnection)
|
||||||
def get_txids_by_asset_id(conn, asset_id):
|
def get_txids_by_asset_id(conn, asset_id):
|
||||||
# get the txid of the create transaction for asset_id
|
|
||||||
cursor = conn.db['bigchain'].aggregate([
|
|
||||||
{'$match': {
|
|
||||||
'block.transactions.id': asset_id,
|
|
||||||
'block.transactions.operation': 'CREATE'
|
|
||||||
}},
|
|
||||||
{'$unwind': '$block.transactions'},
|
|
||||||
{'$match': {
|
|
||||||
'block.transactions.id': asset_id,
|
|
||||||
'block.transactions.operation': 'CREATE'
|
|
||||||
}},
|
|
||||||
{'$project': {'block.transactions.id': True}}
|
|
||||||
])
|
|
||||||
create_tx_txids = (elem['block']['transactions']['id'] for elem in cursor)
|
|
||||||
|
|
||||||
# get txids of transfer transaction with asset_id
|
|
||||||
cursor = conn.db['bigchain'].aggregate([
|
cursor = conn.db['bigchain'].aggregate([
|
||||||
{'$match': {
|
{'$match': {
|
||||||
'block.transactions.asset.id': asset_id
|
'block.transactions.asset.id': asset_id
|
||||||
@ -111,9 +95,7 @@ def get_txids_by_asset_id(conn, asset_id):
|
|||||||
}},
|
}},
|
||||||
{'$project': {'block.transactions.id': True}}
|
{'$project': {'block.transactions.id': True}}
|
||||||
])
|
])
|
||||||
transfer_tx_ids = (elem['block']['transactions']['id'] for elem in cursor)
|
return (elem['block']['transactions']['id'] for elem in cursor)
|
||||||
|
|
||||||
return chain(create_tx_txids, transfer_tx_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(MongoDBConnection)
|
@register_query(MongoDBConnection)
|
||||||
|
@ -103,8 +103,8 @@ definitions:
|
|||||||
description: |
|
description: |
|
||||||
Description of the asset being transacted. In the case of a ``TRANSFER``
|
Description of the asset being transacted. In the case of a ``TRANSFER``
|
||||||
transaction, this field contains only the ID of asset. In the case
|
transaction, this field contains only the ID of asset. In the case
|
||||||
of a ``CREATE`` transaction, this field contains only the user-defined
|
of a ``CREATE`` transaction, this field contains the user-defined
|
||||||
payload.
|
payload and may contain the asset ID (duplicated from the Transaction ID).
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
|
@ -444,6 +444,7 @@ class Transaction(object):
|
|||||||
asset is not None and not (isinstance(asset, dict) and 'data' in asset)):
|
asset is not None and not (isinstance(asset, dict) and 'data' in asset)):
|
||||||
raise TypeError(('`asset` must be None or a dict holding a `data` '
|
raise TypeError(('`asset` must be None or a dict holding a `data` '
|
||||||
" property instance for '{}' Transactions".format(operation)))
|
" property instance for '{}' Transactions".format(operation)))
|
||||||
|
asset.pop('id', None) # Remove duplicated asset ID if there is one
|
||||||
elif (operation == Transaction.TRANSFER and
|
elif (operation == Transaction.TRANSFER and
|
||||||
not (isinstance(asset, dict) and 'id' in asset)):
|
not (isinstance(asset, dict) and 'id' in asset)):
|
||||||
raise TypeError(('`asset` must be a dict holding an `id` property '
|
raise TypeError(('`asset` must be a dict holding an `id` property '
|
||||||
@ -926,9 +927,11 @@ class Transaction(object):
|
|||||||
|
|
||||||
tx_no_signatures = Transaction._remove_signatures(tx)
|
tx_no_signatures = Transaction._remove_signatures(tx)
|
||||||
tx_serialized = Transaction._to_str(tx_no_signatures)
|
tx_serialized = Transaction._to_str(tx_no_signatures)
|
||||||
tx_id = Transaction._to_hash(tx_serialized)
|
tx['id'] = Transaction._to_hash(tx_serialized)
|
||||||
|
if self.operation == Transaction.CREATE:
|
||||||
tx['id'] = tx_id
|
# Duplicate asset into asset for consistency with TRANSFER
|
||||||
|
# transactions
|
||||||
|
tx['asset']['id'] = tx['id']
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -952,6 +955,9 @@ class Transaction(object):
|
|||||||
# case could yield incorrect signatures. This is why we only
|
# case could yield incorrect signatures. This is why we only
|
||||||
# set it to `None` if it's set in the dict.
|
# set it to `None` if it's set in the dict.
|
||||||
input_['fulfillment'] = None
|
input_['fulfillment'] = None
|
||||||
|
# Pop duplicated asset_id from CREATE tx
|
||||||
|
if tx_dict['operation'] == Transaction.CREATE:
|
||||||
|
tx_dict['asset'].pop('id', None)
|
||||||
return tx_dict
|
return tx_dict
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -1031,6 +1037,10 @@ class Transaction(object):
|
|||||||
"the hash of its body, i.e. it's not valid.")
|
"the hash of its body, i.e. it's not valid.")
|
||||||
raise InvalidHash(err_msg.format(proposed_tx_id))
|
raise InvalidHash(err_msg.format(proposed_tx_id))
|
||||||
|
|
||||||
|
if tx_body.get('operation') == Transaction.CREATE:
|
||||||
|
if proposed_tx_id != tx_body['asset'].get('id'):
|
||||||
|
raise InvalidHash("CREATE tx has wrong asset_id")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, tx):
|
def from_dict(cls, tx):
|
||||||
"""Transforms a Python dictionary to a Transaction object.
|
"""Transforms a Python dictionary to a Transaction object.
|
||||||
|
@ -300,6 +300,7 @@ def test_transaction_serialization(user_input, user_output, data):
|
|||||||
'operation': Transaction.CREATE,
|
'operation': Transaction.CREATE,
|
||||||
'metadata': None,
|
'metadata': None,
|
||||||
'asset': {
|
'asset': {
|
||||||
|
'id': tx_id,
|
||||||
'data': data,
|
'data': data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +308,7 @@ def test_transaction_serialization(user_input, user_output, data):
|
|||||||
tx = Transaction(Transaction.CREATE, {'data': data}, [user_input],
|
tx = Transaction(Transaction.CREATE, {'data': data}, [user_input],
|
||||||
[user_output])
|
[user_output])
|
||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict['id'] = tx_id
|
tx_dict['id'] = tx_dict['asset']['id'] = tx_id
|
||||||
|
|
||||||
assert tx_dict == expected
|
assert tx_dict == expected
|
||||||
|
|
||||||
@ -334,6 +335,7 @@ def test_transaction_deserialization(user_input, user_output, data):
|
|||||||
}
|
}
|
||||||
tx_no_signatures = Transaction._remove_signatures(tx)
|
tx_no_signatures = Transaction._remove_signatures(tx)
|
||||||
tx['id'] = Transaction._to_hash(Transaction._to_str(tx_no_signatures))
|
tx['id'] = Transaction._to_hash(Transaction._to_str(tx_no_signatures))
|
||||||
|
tx['asset']['id'] = tx['id']
|
||||||
tx = Transaction.from_dict(tx)
|
tx = Transaction.from_dict(tx)
|
||||||
|
|
||||||
assert tx == expected
|
assert tx == expected
|
||||||
@ -680,6 +682,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data):
|
|||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict['inputs'][0]['fulfillment'] = None
|
tx_dict['inputs'][0]['fulfillment'] = None
|
||||||
tx_dict.pop('id')
|
tx_dict.pop('id')
|
||||||
|
tx_dict['asset'].pop('id')
|
||||||
|
|
||||||
assert tx_dict == expected
|
assert tx_dict == expected
|
||||||
|
|
||||||
@ -763,6 +766,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
|
|||||||
metadata=data, asset=data)
|
metadata=data, asset=data)
|
||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict.pop('id')
|
tx_dict.pop('id')
|
||||||
|
tx_dict['asset'].pop('id')
|
||||||
tx_dict['inputs'][0]['fulfillment'] = None
|
tx_dict['inputs'][0]['fulfillment'] = None
|
||||||
|
|
||||||
assert tx_dict == expected
|
assert tx_dict == expected
|
||||||
@ -975,3 +979,25 @@ def test_validate_version(utx):
|
|||||||
utx.version = '1.0.0'
|
utx.version = '1.0.0'
|
||||||
with raises(SchemaValidationError):
|
with raises(SchemaValidationError):
|
||||||
validate_transaction_model(utx)
|
validate_transaction_model(utx)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_tx_has_asset_id(tx):
|
||||||
|
tx = tx.to_dict()
|
||||||
|
assert tx['id'] == tx['asset']['id']
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_tx_validates_asset_id(tx):
|
||||||
|
from bigchaindb.common.transaction import Transaction
|
||||||
|
from bigchaindb.common.exceptions import InvalidHash
|
||||||
|
|
||||||
|
tx = tx.to_dict()
|
||||||
|
|
||||||
|
# Test fails with wrong asset_id
|
||||||
|
tx['asset']['id'] = tx['asset']['id'][::-1]
|
||||||
|
with raises(InvalidHash):
|
||||||
|
Transaction.from_dict(tx)
|
||||||
|
|
||||||
|
# Test fails with no asset_id
|
||||||
|
tx['asset'].pop('id')
|
||||||
|
with raises(InvalidHash):
|
||||||
|
Transaction.from_dict(tx)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user