mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Added docstrings and tests to new methods
This commit is contained in:
parent
8c0dbeb281
commit
aacba571f8
@ -108,8 +108,8 @@ def create_votes_secondary_index(conn, dbname):
|
|||||||
def create_assets_secondary_index(conn, dbname):
|
def create_assets_secondary_index(conn, dbname):
|
||||||
logger.info('Create `assets` secondary index.')
|
logger.info('Create `assets` secondary index.')
|
||||||
|
|
||||||
# is the first index redundant then?
|
# unique index on the id of the asset.
|
||||||
# compound index to order votes by block id and node
|
# the id is the txid of the transaction that created the asset
|
||||||
conn.conn[dbname]['assets'].create_index('id',
|
conn.conn[dbname]['assets'].create_index('id',
|
||||||
name='asset_id',
|
name='asset_id',
|
||||||
unique=True)
|
unique=True)
|
||||||
|
@ -213,13 +213,28 @@ def get_block(connection, block_id):
|
|||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def write_assets(connection, assets):
|
def write_assets(connection, assets):
|
||||||
# TODO: write docstring
|
"""Write a list of assets to the assets table.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
assets (list): a list of assets to write.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The database response.
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def get_assets(connection, assets):
|
def get_assets(connection, asset_ids):
|
||||||
# TODO: write docstring
|
"""Get a list of assets from the assets table.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
asset_ids (list): a of list of ids for the assets to be retrieved from
|
||||||
|
the database.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
assets (list): the list of returned assets.
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,13 +315,33 @@ class Block(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_db(cls, bigchain, block_dict):
|
def from_db(cls, bigchain, block_dict):
|
||||||
|
"""
|
||||||
|
Helper method that reconstructs a block_dict that was returned from
|
||||||
|
the database. If checks what asset_ids to retrieve, retrieves the
|
||||||
|
assets from the assets table and reconstructs the block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bigchain (:class:`~bigchaindb.Bigchain`): An instance of Bigchain
|
||||||
|
used to perform database queries.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`~Block`
|
||||||
|
|
||||||
|
"""
|
||||||
asset_ids = cls.get_asset_ids(block_dict)
|
asset_ids = cls.get_asset_ids(block_dict)
|
||||||
assets = bigchain.get_assets(asset_ids)
|
assets = bigchain.get_assets(asset_ids)
|
||||||
block_dict = cls.couple_assets(block_dict, assets)
|
block_dict = cls.couple_assets(block_dict, assets)
|
||||||
return cls.from_dict(block_dict)
|
return cls.from_dict(block_dict)
|
||||||
|
|
||||||
def decouple_assets(self):
|
def decouple_assets(self):
|
||||||
# TODO: Write documentation
|
"""
|
||||||
|
Extracts the assets from the `CREATE` transactions in the block.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (assets, block) with the assets being a list of dicts and
|
||||||
|
the block being the dict of the block with no assets in the CREATE
|
||||||
|
transactions.
|
||||||
|
"""
|
||||||
block_dict = deepcopy(self.to_dict())
|
block_dict = deepcopy(self.to_dict())
|
||||||
assets = []
|
assets = []
|
||||||
for transaction in block_dict['block']['transactions']:
|
for transaction in block_dict['block']['transactions']:
|
||||||
@ -335,7 +355,20 @@ class Block(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def couple_assets(block_dict, assets):
|
def couple_assets(block_dict, assets):
|
||||||
# TODO: Write docstring
|
"""
|
||||||
|
Give a block_dict with not assets (as returned from a database call)
|
||||||
|
and a list of assets, reconstruct the original block by puting the
|
||||||
|
assets back into the `CREATE` transactions in the block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block_dict (:obj:`dict`): The block dict as returned from a
|
||||||
|
database call.
|
||||||
|
assets (:obj:`list` of :obj:`dict`): A list of assets returned from
|
||||||
|
a database call.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The dict of the reconstructed block.
|
||||||
|
"""
|
||||||
# create a dict with {'<txid>': asset}
|
# create a dict with {'<txid>': asset}
|
||||||
assets = {asset.pop('id'): asset for asset in assets}
|
assets = {asset.pop('id'): asset for asset in assets}
|
||||||
# add the assets to the block transactions
|
# add the assets to the block transactions
|
||||||
@ -348,7 +381,19 @@ class Block(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_asset_ids(block_dict):
|
def get_asset_ids(block_dict):
|
||||||
# TODO: Write docstring
|
"""
|
||||||
|
Given a block_dict return all the asset_ids for that block (the txid
|
||||||
|
of CREATE transactions). Usefull to know which assets to retrieve
|
||||||
|
from the database to reconstruct the block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block_dict (:obj:`dict`): The block dict as returned from a
|
||||||
|
database call.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: The list of asset_ids in the block.
|
||||||
|
|
||||||
|
"""
|
||||||
asset_ids = []
|
asset_ids = []
|
||||||
for transaction in block_dict['block']['transactions']:
|
for transaction in block_dict['block']['transactions']:
|
||||||
if transaction['operation'] in [Transaction.CREATE,
|
if transaction['operation'] in [Transaction.CREATE,
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import pymongo
|
||||||
|
|
||||||
pytestmark = pytest.mark.bdb
|
pytestmark = pytest.mark.bdb
|
||||||
|
|
||||||
@ -418,3 +421,46 @@ def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
|||||||
# Test get by asset and TRANSFER
|
# Test get by asset and TRANSFER
|
||||||
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.TRANSFER))
|
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.TRANSFER))
|
||||||
assert txids == {signed_transfer_tx.id}
|
assert txids == {signed_transfer_tx.id}
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_assets():
|
||||||
|
from bigchaindb.backend import connect, query
|
||||||
|
conn = connect()
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'id': 1, 'data': '1'},
|
||||||
|
{'id': 2, 'data': '2'},
|
||||||
|
{'id': 3, 'data': '3'},
|
||||||
|
# Duplicated id. Should not be written to the database
|
||||||
|
{'id': 1, 'data': '1'},
|
||||||
|
]
|
||||||
|
|
||||||
|
# write the assets
|
||||||
|
query.write_assets(conn, deepcopy(assets))
|
||||||
|
|
||||||
|
# check that 3 assets were written to the database
|
||||||
|
cursor = conn.db.assets.find({}, projection={'_id': False})\
|
||||||
|
.sort('id', pymongo.ASCENDING)
|
||||||
|
|
||||||
|
assert cursor.count() == 3
|
||||||
|
assert list(cursor) == assets[:-1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_assets():
|
||||||
|
from bigchaindb.backend import connect, query
|
||||||
|
conn = connect()
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'id': 1, 'data': '1'},
|
||||||
|
{'id': 2, 'data': '2'},
|
||||||
|
{'id': 3, 'data': '3'},
|
||||||
|
]
|
||||||
|
|
||||||
|
# write the assets
|
||||||
|
conn.db.assets.insert_many(deepcopy(assets), ordered=False)
|
||||||
|
|
||||||
|
# read only 2 assets
|
||||||
|
cursor = query.get_assets(conn, [1, 3])
|
||||||
|
|
||||||
|
assert cursor.count() == 2
|
||||||
|
assert list(cursor.sort('id', pymongo.ASCENDING)) == assets[::2]
|
||||||
|
@ -153,3 +153,136 @@ class TestBlockModel(object):
|
|||||||
block = b.create_block([tx, tx])
|
block = b.create_block([tx, tx])
|
||||||
with raises(DuplicateTransaction):
|
with raises(DuplicateTransaction):
|
||||||
block._validate_block(b)
|
block._validate_block(b)
|
||||||
|
|
||||||
|
def test_decouple_assets(self, b):
|
||||||
|
from bigchaindb.models import Block, Transaction
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'msg': '1'},
|
||||||
|
{'msg': '2'},
|
||||||
|
{'msg': '3'},
|
||||||
|
]
|
||||||
|
|
||||||
|
txs = []
|
||||||
|
# create 3 assets
|
||||||
|
for asset in assets:
|
||||||
|
tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create a `TRANSFER` transaction.
|
||||||
|
# the asset in `TRANSFER` transactions is not extracted
|
||||||
|
tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
|
||||||
|
asset_id=txs[0].id)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create the block
|
||||||
|
block = Block(txs)
|
||||||
|
# decouple assets
|
||||||
|
assets_from_block, block_dict = block.decouple_assets()
|
||||||
|
|
||||||
|
assert len(assets_from_block) == 3
|
||||||
|
for i in range(3):
|
||||||
|
assert assets_from_block[i]['data'] == assets[i]
|
||||||
|
assert assets_from_block[i]['id'] == txs[i].id
|
||||||
|
|
||||||
|
# check the `TRANSFER` transaction was not changed
|
||||||
|
assert block.transactions[3].to_dict() == \
|
||||||
|
block_dict['block']['transactions'][3]
|
||||||
|
|
||||||
|
def test_couple_assets(self, b):
|
||||||
|
from bigchaindb.models import Block, Transaction
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'msg': '1'},
|
||||||
|
{'msg': '2'},
|
||||||
|
{'msg': '3'},
|
||||||
|
]
|
||||||
|
|
||||||
|
txs = []
|
||||||
|
# create 3 assets
|
||||||
|
for asset in assets:
|
||||||
|
tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create a `TRANSFER` transaction.
|
||||||
|
# the asset in `TRANSFER` transactions is not extracted
|
||||||
|
tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
|
||||||
|
asset_id=txs[0].id)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create the block
|
||||||
|
block = Block(txs)
|
||||||
|
# decouple assets
|
||||||
|
assets_from_block, block_dict = block.decouple_assets()
|
||||||
|
|
||||||
|
# reconstruct the block
|
||||||
|
block_dict_reconstructed = Block.couple_assets(block_dict,
|
||||||
|
assets_from_block)
|
||||||
|
|
||||||
|
# check that the reconstructed block is the as the original block
|
||||||
|
assert block == Block.from_dict(block_dict_reconstructed)
|
||||||
|
|
||||||
|
def test_get_asset_ids(self, b):
|
||||||
|
from bigchaindb.models import Block, Transaction
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'msg': '1'},
|
||||||
|
{'msg': '2'},
|
||||||
|
{'msg': '3'},
|
||||||
|
]
|
||||||
|
|
||||||
|
txs = []
|
||||||
|
# create 3 assets
|
||||||
|
for asset in assets:
|
||||||
|
tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create a `TRANSFER` transaction.
|
||||||
|
# the asset in `TRANSFER` transactions is not extracted
|
||||||
|
tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
|
||||||
|
asset_id=txs[0].id)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create the block
|
||||||
|
block = Block(txs)
|
||||||
|
# decouple assets
|
||||||
|
assets_from_block, block_dict = block.decouple_assets()
|
||||||
|
|
||||||
|
# get the asset_ids and check that they are the same as the `CREATE`
|
||||||
|
# transactions
|
||||||
|
asset_ids = Block.get_asset_ids(block_dict)
|
||||||
|
assert asset_ids == [tx.id for tx in txs[:-1]]
|
||||||
|
|
||||||
|
def test_from_db(self, b):
|
||||||
|
from bigchaindb.models import Block, Transaction
|
||||||
|
|
||||||
|
assets = [
|
||||||
|
{'msg': '1'},
|
||||||
|
{'msg': '2'},
|
||||||
|
{'msg': '3'},
|
||||||
|
]
|
||||||
|
|
||||||
|
txs = []
|
||||||
|
# create 3 assets
|
||||||
|
for asset in assets:
|
||||||
|
tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create a `TRANSFER` transaction.
|
||||||
|
# the asset in `TRANSFER` transactions is not extracted
|
||||||
|
tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
|
||||||
|
asset_id=txs[0].id)
|
||||||
|
txs.append(tx)
|
||||||
|
|
||||||
|
# create the block
|
||||||
|
block = Block(txs)
|
||||||
|
# decouple assets
|
||||||
|
assets_from_block, block_dict = block.decouple_assets()
|
||||||
|
|
||||||
|
# write the assets and block separatedly
|
||||||
|
b.write_assets(assets_from_block)
|
||||||
|
b.write_block(block)
|
||||||
|
|
||||||
|
# check the reconstructed block is the same as the original block
|
||||||
|
block_from_db = Block.from_db(b, block_dict)
|
||||||
|
assert block == block_from_db
|
||||||
|
Loading…
x
Reference in New Issue
Block a user