mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Integrate blocks API (#1970)
* Integrate blocks api * Update docs * Fix docs * Fixed mismatch between code and documentation * Fixed docs
This commit is contained in:
parent
c156d0bfe8
commit
e25d365828
@ -32,6 +32,17 @@ def get_transaction(conn, transaction_id):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_query(LocalMongoDBConnection)
|
||||||
|
def get_transactions(conn, transaction_ids):
|
||||||
|
try:
|
||||||
|
return conn.run(
|
||||||
|
conn.collection('transactions')
|
||||||
|
.find({'id': {'$in': transaction_ids}},
|
||||||
|
projection={'_id': False}))
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@register_query(LocalMongoDBConnection)
|
@register_query(LocalMongoDBConnection)
|
||||||
def store_metadata(conn, metadata):
|
def store_metadata(conn, metadata):
|
||||||
try:
|
try:
|
||||||
@ -153,3 +164,11 @@ def get_spending_transactions(conn, inputs):
|
|||||||
{'$project': {'_id': False}}
|
{'$project': {'_id': False}}
|
||||||
]))
|
]))
|
||||||
return cursor
|
return cursor
|
||||||
|
|
||||||
|
|
||||||
|
@register_query(LocalMongoDBConnection)
|
||||||
|
def get_block(conn, block_id):
|
||||||
|
return conn.run(
|
||||||
|
conn.collection('blocks')
|
||||||
|
.find_one({'height': block_id},
|
||||||
|
projection={'_id': False}))
|
||||||
|
@ -68,6 +68,20 @@ def get_transaction(connection, transaction_id):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def get_transactions(connection, transaction_ids):
|
||||||
|
"""Get transactions from the transactions table.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
transaction_ids (list): list of transaction ids to fetch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The result of the operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def get_asset(connection, asset_id):
|
def get_asset(connection, asset_id):
|
||||||
"""Get a transaction from the transactions table.
|
"""Get a transaction from the transactions table.
|
||||||
|
@ -96,7 +96,7 @@ class Transaction(Transaction):
|
|||||||
return super().from_dict(tx_body)
|
return super().from_dict(tx_body)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_db(cls, bigchain, tx_dict):
|
def from_db(cls, bigchain, tx_dict_list):
|
||||||
"""Helper method that reconstructs a transaction dict that was returned
|
"""Helper method that reconstructs a transaction dict that was returned
|
||||||
from the database. It checks what asset_id to retrieve, retrieves the
|
from the database. It checks what asset_id to retrieve, retrieves the
|
||||||
asset from the asset table and reconstructs the transaction.
|
asset from the asset table and reconstructs the transaction.
|
||||||
@ -104,29 +104,46 @@ class Transaction(Transaction):
|
|||||||
Args:
|
Args:
|
||||||
bigchain (:class:`~bigchaindb.Bigchain`): An instance of Bigchain
|
bigchain (:class:`~bigchaindb.Bigchain`): An instance of Bigchain
|
||||||
used to perform database queries.
|
used to perform database queries.
|
||||||
tx_dict (:obj:`dict`): The transaction dict as returned from the
|
tx_dict_list (:list:`dict` or :obj:`dict`): The transaction dict or
|
||||||
database.
|
list of transaction dict as returned from the database.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:class:`~Transaction`
|
:class:`~Transaction`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if tx_dict['operation'] in [Transaction.CREATE, Transaction.GENESIS]:
|
return_list = True
|
||||||
# TODO: Maybe replace this call to a call to get_asset_by_id
|
if isinstance(tx_dict_list, dict):
|
||||||
asset = list(bigchain.get_assets([tx_dict['id']]))[0]
|
tx_dict_list = [tx_dict_list]
|
||||||
|
return_list = False
|
||||||
|
|
||||||
|
tx_map = {}
|
||||||
|
tx_ids = []
|
||||||
|
for tx in tx_dict_list:
|
||||||
|
tx.update({'metadata': None})
|
||||||
|
tx_map[tx['id']] = tx
|
||||||
|
if tx['operation'] in [Transaction.CREATE, Transaction.GENESIS]:
|
||||||
|
tx_ids.append(tx['id'])
|
||||||
|
|
||||||
|
assets = list(bigchain.get_assets(tx_ids))
|
||||||
|
for asset in assets:
|
||||||
|
tx = tx_map[asset['id']]
|
||||||
del asset['id']
|
del asset['id']
|
||||||
tx_dict.update({'asset': asset})
|
tx.update({'asset': asset})
|
||||||
|
|
||||||
# get metadata of the transaction
|
tx_ids = list(tx_map.keys())
|
||||||
metadata = list(bigchain.get_metadata([tx_dict['id']]))
|
metadata_list = list(bigchain.get_metadata(tx_ids))
|
||||||
if 'metadata' not in tx_dict:
|
for metadata in metadata_list:
|
||||||
metadata = metadata[0] if metadata else None
|
tx = tx_map[metadata['id']]
|
||||||
if metadata:
|
tx.update({'metadata': metadata.get('metadata')})
|
||||||
metadata = metadata.get('metadata')
|
|
||||||
|
|
||||||
tx_dict.update({'metadata': metadata})
|
if return_list:
|
||||||
|
tx_list = []
|
||||||
return cls.from_dict(tx_dict)
|
for tx_id, tx in tx_map.items():
|
||||||
|
tx_list.append(cls.from_dict(tx))
|
||||||
|
return tx_list
|
||||||
|
else:
|
||||||
|
tx = list(tx_map.values())[0]
|
||||||
|
return cls.from_dict(tx)
|
||||||
|
|
||||||
|
|
||||||
class Block(object):
|
class Block(object):
|
||||||
|
@ -31,7 +31,7 @@ class App(BaseApplication):
|
|||||||
def init_chain(self, validators):
|
def init_chain(self, validators):
|
||||||
"""Initialize chain with block of height 0"""
|
"""Initialize chain with block of height 0"""
|
||||||
|
|
||||||
block = Block(app_hash='', height=0)
|
block = Block(app_hash='', height=0, transactions=[])
|
||||||
self.bigchaindb.store_block(block._asdict())
|
self.bigchaindb.store_block(block._asdict())
|
||||||
|
|
||||||
def info(self):
|
def info(self):
|
||||||
@ -112,7 +112,9 @@ class App(BaseApplication):
|
|||||||
|
|
||||||
# register a new block only when new transactions are received
|
# register a new block only when new transactions are received
|
||||||
if self.block_txn_ids:
|
if self.block_txn_ids:
|
||||||
block = Block(app_hash=self.block_txn_hash, height=self.new_height)
|
block = Block(app_hash=self.block_txn_hash,
|
||||||
|
height=self.new_height,
|
||||||
|
transactions=self.block_txn_ids)
|
||||||
self.bigchaindb.store_block(block._asdict())
|
self.bigchaindb.store_block(block._asdict())
|
||||||
|
|
||||||
data = self.block_txn_hash.encode('utf-8')
|
data = self.block_txn_hash.encode('utf-8')
|
||||||
|
@ -116,6 +116,42 @@ class BigchainDB(Bigchain):
|
|||||||
|
|
||||||
return backend.query.get_latest_block(self.connection)
|
return backend.query.get_latest_block(self.connection)
|
||||||
|
|
||||||
|
def get_block(self, block_id, include_status=False):
|
||||||
|
"""Get the block with the specified `block_id` (and optionally its status)
|
||||||
|
|
||||||
|
Returns the block corresponding to `block_id` or None if no match is
|
||||||
|
found.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block_id (str): block id of the block to get
|
||||||
|
include_status (bool): also return the status of the block
|
||||||
|
the return value is then a tuple: (block, status)
|
||||||
|
"""
|
||||||
|
# get block from database
|
||||||
|
if isinstance(block_id, str):
|
||||||
|
block_id = int(block_id)
|
||||||
|
|
||||||
|
block = backend.query.get_block(self.connection, block_id)
|
||||||
|
if block:
|
||||||
|
transactions = backend.query.get_transactions(self.connection, block['transactions'])
|
||||||
|
transactions = Transaction.from_db(self, transactions)
|
||||||
|
|
||||||
|
block = {'height': block['height'],
|
||||||
|
'transactions': []}
|
||||||
|
block_txns = block['transactions']
|
||||||
|
for txn in transactions:
|
||||||
|
block_txns.append(txn.to_dict())
|
||||||
|
|
||||||
|
status = None
|
||||||
|
if include_status:
|
||||||
|
# NOTE: (In Tendermint) a block is an abstract entity which
|
||||||
|
# exists only after it has been validated
|
||||||
|
if block:
|
||||||
|
status = self.BLOCK_VALID
|
||||||
|
return block, status
|
||||||
|
else:
|
||||||
|
return block
|
||||||
|
|
||||||
def validate_transaction(self, tx):
|
def validate_transaction(self, tx):
|
||||||
"""Validate a transaction against the current status of the database."""
|
"""Validate a transaction against the current status of the database."""
|
||||||
|
|
||||||
@ -142,4 +178,4 @@ class BigchainDB(Bigchain):
|
|||||||
return fastquery.FastQuery(self.connection, self.me)
|
return fastquery.FastQuery(self.connection, self.me)
|
||||||
|
|
||||||
|
|
||||||
Block = namedtuple('Block', ('app_hash', 'height'))
|
Block = namedtuple('Block', ('app_hash', 'height', 'transactions'))
|
||||||
|
@ -7,6 +7,7 @@ import os.path
|
|||||||
from bigchaindb.common.transaction import Transaction, Input, TransactionLink
|
from bigchaindb.common.transaction import Transaction, Input, TransactionLink
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.core import Bigchain
|
||||||
from bigchaindb.models import Block
|
from bigchaindb.models import Block
|
||||||
|
from bigchaindb.tendermint import lib
|
||||||
from bigchaindb.web import server
|
from bigchaindb.web import server
|
||||||
|
|
||||||
|
|
||||||
@ -242,18 +243,24 @@ def main():
|
|||||||
node_private = "5G2kE1zJAgTajkVSbPAQWo4c2izvtwqaNHYsaNpbbvxX"
|
node_private = "5G2kE1zJAgTajkVSbPAQWo4c2izvtwqaNHYsaNpbbvxX"
|
||||||
node_public = "DngBurxfeNVKZWCEcDnLj1eMPAS7focUZTE5FndFGuHT"
|
node_public = "DngBurxfeNVKZWCEcDnLj1eMPAS7focUZTE5FndFGuHT"
|
||||||
signature = "53wxrEQDYk1dXzmvNSytbCfmNVnPqPkDQaTnAe8Jf43s6ssejPxezkCvUnGTnduNUmaLjhaan1iRLi3peu6s5DzA"
|
signature = "53wxrEQDYk1dXzmvNSytbCfmNVnPqPkDQaTnAe8Jf43s6ssejPxezkCvUnGTnduNUmaLjhaan1iRLi3peu6s5DzA"
|
||||||
block = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature)
|
|
||||||
ctx['block'] = pretty_json(block.to_dict())
|
|
||||||
ctx['blockid'] = block.id
|
|
||||||
|
|
||||||
|
app_hash = 'f6e0c49c6d94d6924351f25bb334cf2a99af4206339bf784e741d1a5ab599056'
|
||||||
|
block = lib.Block(height=1, transactions=[tx.to_dict()], app_hash=app_hash)
|
||||||
|
block_dict = block._asdict()
|
||||||
|
block_dict.pop('app_hash')
|
||||||
|
ctx['block'] = pretty_json(block_dict)
|
||||||
|
ctx['blockid'] = block.height
|
||||||
|
|
||||||
|
block = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature)
|
||||||
block_transfer = Block(transactions=[tx_transfer], node_pubkey=node_public,
|
block_transfer = Block(transactions=[tx_transfer], node_pubkey=node_public,
|
||||||
voters=[node_public], signature=signature)
|
voters=[node_public], signature=signature)
|
||||||
ctx['block_transfer'] = pretty_json(block.to_dict())
|
ctx['block_transfer'] = pretty_json(block_transfer.to_dict())
|
||||||
|
|
||||||
# vote
|
# vote
|
||||||
|
vblock = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature)
|
||||||
DUMMY_SHA3 = '0123456789abcdef' * 4
|
DUMMY_SHA3 = '0123456789abcdef' * 4
|
||||||
b = Bigchain(public_key=node_public, private_key=node_private)
|
b = Bigchain(public_key=node_public, private_key=node_private)
|
||||||
vote = b.vote(block.id, DUMMY_SHA3, True)
|
vote = b.vote(vblock.id, DUMMY_SHA3, True)
|
||||||
ctx['vote'] = pretty_json(vote)
|
ctx['vote'] = pretty_json(vote)
|
||||||
|
|
||||||
# block status
|
# block status
|
||||||
|
@ -9,82 +9,23 @@ A block must contain the following JSON keys
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"id": "<ID of the block>",
|
"height": "<Height of the block>",
|
||||||
"block": {
|
"transactions": ["<List of transactions>"]
|
||||||
"timestamp": "<Block-creation timestamp>",
|
|
||||||
"transactions": ["<List of transactions>"],
|
|
||||||
"node_pubkey": "<Public key of the node which created the block>",
|
|
||||||
"voters": ["<List of public keys of all nodes in the cluster>"]
|
|
||||||
},
|
|
||||||
"signature": "<Signature of inner block object>"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
The JSON Keys in a Block
|
The JSON Keys in a Block
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
**id**
|
**height**
|
||||||
|
|
||||||
The transaction ID and also the SHA3-256 hash
|
The block ``"height"`` (``integer``) denotes the height of the blockchain when the given block was committed.
|
||||||
of the inner ``block`` object, loosely speaking.
|
Since the blockchain height increases monotonically the height of block can be regarded as its id.
|
||||||
It's a string.
|
|
||||||
To compute it, 1) construct an :term:`associative array` ``d`` containing
|
**NOTE**: The genesis block has height ``0``
|
||||||
``block.timestamp``, ``block.transactions``, ``block.node_pubkey``,
|
|
||||||
``block.voters``, and their values. 2) compute ``id = hash_of_aa(d)``.
|
|
||||||
There's pseudocode for the ``hash_of_aa()`` function
|
|
||||||
in the `IPDB Transaction Spec page about cryptographic hashes
|
|
||||||
<https://the-ipdb-transaction-spec.readthedocs.io/en/latest/common-operations/crypto-hashes.html#computing-the-hash-of-an-associative-array>`_.
|
|
||||||
The result (``id``) is a string: the block ID.
|
|
||||||
An example is ``"b60adf655932bf47ef58c0bfb2dd276d4795b94346b36cbb477e10d7eb02cea8"``
|
|
||||||
|
|
||||||
|
|
||||||
**block.timestamp**
|
**transactions**
|
||||||
|
|
||||||
The `Unix time <https://en.wikipedia.org/wiki/Unix_time>`_
|
|
||||||
when the block was created, according to the node which created it.
|
|
||||||
It's a string representation of an integer.
|
|
||||||
An example is ``"1507294217"``.
|
|
||||||
|
|
||||||
|
|
||||||
**block.transactions**
|
|
||||||
|
|
||||||
A list of the :ref:`transactions <The Transaction Model>` included in the block.
|
A list of the :ref:`transactions <The Transaction Model>` included in the block.
|
||||||
(Each transaction is a JSON object.)
|
(Each transaction is a JSON object.)
|
||||||
|
|
||||||
|
|
||||||
**block.node_pubkey**
|
|
||||||
|
|
||||||
The public key of the node that created the block.
|
|
||||||
It's a string.
|
|
||||||
See the `IPDB Transaction Spec page about cryptographic keys & signatures
|
|
||||||
<https://the-ipdb-transaction-spec.readthedocs.io/en/latest/common-operations/crypto-keys-and-sigs.html>`_.
|
|
||||||
|
|
||||||
|
|
||||||
**block.voters**
|
|
||||||
|
|
||||||
A list of the public keys of all cluster nodes at the time the block was created.
|
|
||||||
It's a list of strings.
|
|
||||||
This list can change from block to block, as nodes join and leave the cluster.
|
|
||||||
|
|
||||||
|
|
||||||
**signature**
|
|
||||||
|
|
||||||
The cryptographic signature of the inner ``block``
|
|
||||||
by the node that created the block
|
|
||||||
(i.e. the node with public key ``node_pubkey``).
|
|
||||||
To compute that:
|
|
||||||
|
|
||||||
#. Construct an :term:`associative array` ``d`` containing the contents
|
|
||||||
of the inner ``block``
|
|
||||||
(i.e. ``block.timestamp``, ``block.transactions``, ``block.node_pubkey``,
|
|
||||||
``block.voters``, and their values).
|
|
||||||
#. Compute ``signature = sig_of_aa(d, private_key)``,
|
|
||||||
where ``private_key`` is the node's private key
|
|
||||||
(i.e. ``node_pubkey`` and ``private_key`` are a key pair). There's pseudocode
|
|
||||||
for the ``sig_of_aa()`` function
|
|
||||||
on `the IPDB Transaction Spec page about cryptographic keys and signatures
|
|
||||||
<https://the-ipdb-transaction-spec.readthedocs.io/en/latest/common-operations/crypto-keys-and-sigs.html#computing-the-signature-of-an-associative-array>`_.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The ``d_bytes`` computed when computing the block ID will be the *same* as the ``d_bytes`` computed when computing the block signature. This can be used to avoid redundant calculations.
|
|
||||||
|
@ -597,14 +597,12 @@ The `votes endpoint <#votes>`_ contains all the voting information for a specifi
|
|||||||
Blocks
|
Blocks
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. http:get:: /api/v1/blocks/{block_id}
|
.. http:get:: /api/v1/blocks/{block_height}
|
||||||
|
|
||||||
Get the block with the ID ``block_id``. Any blocks, be they ``VALID``, ``UNDECIDED`` or ``INVALID`` will be
|
Get the block with the height ``block_height``.
|
||||||
returned. To check a block's status independently, use the `Statuses endpoint <#status>`_.
|
|
||||||
To check the votes on a block, have a look at the `votes endpoint <#votes>`_.
|
|
||||||
|
|
||||||
:param block_id: block ID
|
:param block_height: block ID
|
||||||
:type block_id: hex string
|
:type block_height: integer
|
||||||
|
|
||||||
**Example request**:
|
**Example request**:
|
||||||
|
|
||||||
@ -620,7 +618,7 @@ Blocks
|
|||||||
:resheader Content-Type: ``application/json``
|
:resheader Content-Type: ``application/json``
|
||||||
|
|
||||||
:statuscode 200: A block with that ID was found.
|
:statuscode 200: A block with that ID was found.
|
||||||
:statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks`` without the ``block_id``.
|
:statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks`` without the ``block_height``.
|
||||||
:statuscode 404: A block with that ID was not found.
|
:statuscode 404: A block with that ID was not found.
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,3 +152,31 @@ def test_get_spending_transactions(user_pk, user_sk):
|
|||||||
|
|
||||||
# tx3 not a member because input 1 not asked for
|
# tx3 not a member because input 1 not asked for
|
||||||
assert txns == [tx2.to_dict(), tx4.to_dict()]
|
assert txns == [tx2.to_dict(), tx4.to_dict()]
|
||||||
|
|
||||||
|
|
||||||
|
def test_store_block():
|
||||||
|
from bigchaindb.backend import connect, query
|
||||||
|
from bigchaindb.tendermint.lib import Block
|
||||||
|
conn = connect()
|
||||||
|
|
||||||
|
block = Block(app_hash='random_utxo',
|
||||||
|
height=3,
|
||||||
|
transactions=[])
|
||||||
|
query.store_block(conn, block._asdict())
|
||||||
|
cursor = conn.db.blocks.find({}, projection={'_id': False})
|
||||||
|
assert cursor.count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_block():
|
||||||
|
from bigchaindb.backend import connect, query
|
||||||
|
from bigchaindb.tendermint.lib import Block
|
||||||
|
conn = connect()
|
||||||
|
|
||||||
|
block = Block(app_hash='random_utxo',
|
||||||
|
height=3,
|
||||||
|
transactions=[])
|
||||||
|
|
||||||
|
conn.db.blocks.insert_one(block._asdict())
|
||||||
|
|
||||||
|
block = dict(query.get_block(conn, 3))
|
||||||
|
assert block['height'] == 3
|
||||||
|
@ -12,12 +12,13 @@ pytestmark = pytest.mark.tendermint
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_app(b):
|
def test_app(tb):
|
||||||
from bigchaindb.tendermint import App
|
from bigchaindb.tendermint import App
|
||||||
from bigchaindb.tendermint.utils import calculate_hash
|
from bigchaindb.tendermint.utils import calculate_hash
|
||||||
from bigchaindb.common.crypto import generate_key_pair
|
from bigchaindb.common.crypto import generate_key_pair
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
|
|
||||||
|
b = tb
|
||||||
app = App(b)
|
app = App(b)
|
||||||
p = ProtocolHandler(app)
|
p = ProtocolHandler(app)
|
||||||
|
|
||||||
|
@ -37,12 +37,15 @@ def test_asset_is_separated_from_transaciton(b):
|
|||||||
assert b.get_transaction(tx.id) == tx
|
assert b.get_transaction(tx.id) == tx
|
||||||
|
|
||||||
|
|
||||||
def test_get_latest_block(b):
|
def test_get_latest_block(tb):
|
||||||
from bigchaindb.tendermint.lib import Block
|
from bigchaindb.tendermint.lib import Block
|
||||||
|
|
||||||
|
b = tb
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
app_hash = os.urandom(16).hex()
|
app_hash = os.urandom(16).hex()
|
||||||
block = Block(app_hash=app_hash, height=i)._asdict()
|
txn_id = os.urandom(16).hex()
|
||||||
|
block = Block(app_hash=app_hash, height=i,
|
||||||
|
transactions=[txn_id])._asdict()
|
||||||
b.store_block(block)
|
b.store_block(block)
|
||||||
|
|
||||||
block = b.get_latest_block()
|
block = b.get_latest_block()
|
||||||
|
@ -4,6 +4,7 @@ import rethinkdb as r
|
|||||||
|
|
||||||
from bigchaindb.backend.mongodb.connection import MongoDBConnection
|
from bigchaindb.backend.mongodb.connection import MongoDBConnection
|
||||||
from bigchaindb.backend.rethinkdb.connection import RethinkDBConnection
|
from bigchaindb.backend.rethinkdb.connection import RethinkDBConnection
|
||||||
|
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
@ -47,6 +48,15 @@ def flush_mongo_db(connection, dbname):
|
|||||||
connection.conn[dbname].metadata.delete_many({})
|
connection.conn[dbname].metadata.delete_many({})
|
||||||
|
|
||||||
|
|
||||||
|
@flush_db.register(LocalMongoDBConnection)
|
||||||
|
def flush_localmongo_db(connection, dbname):
|
||||||
|
connection.conn[dbname].bigchain.delete_many({})
|
||||||
|
connection.conn[dbname].blocks.delete_many({})
|
||||||
|
connection.conn[dbname].transactions.delete_many({})
|
||||||
|
connection.conn[dbname].assets.delete_many({})
|
||||||
|
connection.conn[dbname].metadata.delete_many({})
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def update_table_config(connection, table, **kwrgas):
|
def update_table_config(connection, table, **kwrgas):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
37
tests/web/test_block_tendermint.py
Normal file
37
tests/web/test_block_tendermint.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
from bigchaindb.tendermint.lib import Block
|
||||||
|
|
||||||
|
BLOCKS_ENDPOINT = '/api/v1/blocks/'
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.tendermint
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.bdb
|
||||||
|
@pytest.mark.usefixtures('inputs')
|
||||||
|
def test_get_block_endpoint(tb, client):
|
||||||
|
b = tb
|
||||||
|
tx = Transaction.create([b.me], [([b.me], 1)], asset={'cycle': 'hero'})
|
||||||
|
tx = tx.sign([b.me_private])
|
||||||
|
b.store_transaction(tx)
|
||||||
|
|
||||||
|
block = Block(app_hash='random_utxo',
|
||||||
|
height=31,
|
||||||
|
transactions=[tx.id])
|
||||||
|
b.store_block(block._asdict())
|
||||||
|
|
||||||
|
res = client.get(BLOCKS_ENDPOINT + str(block.height))
|
||||||
|
expected_response = {'height': block.height, 'transactions': [tx.to_dict()]}
|
||||||
|
assert res.json == expected_response
|
||||||
|
assert res.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.bdb
|
||||||
|
@pytest.mark.usefixtures('inputs')
|
||||||
|
def test_get_block_returns_404_if_not_found(client):
|
||||||
|
res = client.get(BLOCKS_ENDPOINT + '123')
|
||||||
|
assert res.status_code == 404
|
||||||
|
|
||||||
|
res = client.get(BLOCKS_ENDPOINT + '123/')
|
||||||
|
assert res.status_code == 404
|
Loading…
x
Reference in New Issue
Block a user