mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00

Most changes done to how we write and read blocks to the database. Created schema, indexes and queries for mongodb. Fixed tests.
421 lines
13 KiB
Python
421 lines
13 KiB
Python
import pytest
|
|
|
|
pytestmark = pytest.mark.bdb
|
|
|
|
|
|
def test_write_transaction(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# write the transaction
|
|
query.write_transaction(conn, signed_create_tx.to_dict())
|
|
|
|
# get the transaction
|
|
tx_db = conn.db.backlog.find_one({'id': signed_create_tx.id},
|
|
{'_id': False})
|
|
|
|
assert tx_db == signed_create_tx.to_dict()
|
|
|
|
|
|
def test_update_transaction(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# update_transaction can update any field we want, but lets update the
|
|
# same fields that are updated by bigchaindb core.
|
|
signed_create_tx = signed_create_tx.to_dict()
|
|
signed_create_tx.update({'assignee': 'aaa', 'assignment_timestamp': 10})
|
|
conn.db.backlog.insert_one(signed_create_tx)
|
|
|
|
query.update_transaction(conn, signed_create_tx['id'],
|
|
{'assignee': 'bbb', 'assignment_timestamp': 20})
|
|
|
|
tx_db = conn.db.backlog.find_one({'id': signed_create_tx['id']},
|
|
{'_id': False})
|
|
|
|
assert tx_db['assignee'] == 'bbb'
|
|
assert tx_db['assignment_timestamp'] == 20
|
|
|
|
|
|
def test_delete_transaction(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# write_the transaction
|
|
result = conn.db.backlog.insert_one(signed_create_tx.to_dict())
|
|
|
|
# delete transaction
|
|
query.delete_transaction(conn, signed_create_tx.id)
|
|
|
|
tx_db = conn.db.backlog.find_one({'_id': result.inserted_id})
|
|
assert tx_db is None
|
|
|
|
|
|
def test_get_stale_transactions(signed_create_tx):
|
|
import time
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# create two transaction, one of them stale
|
|
tx1 = signed_create_tx.to_dict()
|
|
tx1.update({'id': 'notstale', 'assignment_timestamp': time.time()})
|
|
tx2 = signed_create_tx.to_dict()
|
|
tx2.update({'id': 'stale', 'assignment_timestamp': time.time() - 60})
|
|
|
|
# write the transactions
|
|
conn.db.backlog.insert_one(tx1)
|
|
conn.db.backlog.insert_one(tx2)
|
|
|
|
# get stale transactions
|
|
stale_txs = list(query.get_stale_transactions(conn, 30))
|
|
|
|
assert len(stale_txs) == 1
|
|
assert stale_txs[0]['id'] == 'stale'
|
|
|
|
|
|
def test_get_transaction_from_block(user_pk):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Transaction, Block
|
|
conn = connect()
|
|
|
|
# create a block with 2 transactions
|
|
txs = [
|
|
Transaction.create([user_pk], [([user_pk], 1)]),
|
|
Transaction.create([user_pk], [([user_pk], 1)]),
|
|
]
|
|
block = Block(transactions=txs)
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
tx_db = query.get_transaction_from_block(conn, txs[0].id, block.id)
|
|
assert tx_db == txs[0].to_dict()
|
|
|
|
assert query.get_transaction_from_block(conn, txs[0].id, 'aaa') is None
|
|
assert query.get_transaction_from_block(conn, 'aaa', block.id) is None
|
|
|
|
|
|
def test_get_transaction_from_backlog(create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# insert transaction
|
|
conn.db.backlog.insert_one(create_tx.to_dict())
|
|
|
|
# query the backlog
|
|
tx_db = query.get_transaction_from_backlog(conn, create_tx.id)
|
|
|
|
assert tx_db == create_tx.to_dict()
|
|
|
|
|
|
def test_get_block_status_from_transaction(create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create a block
|
|
block = Block(transactions=[create_tx], voters=['aaa', 'bbb', 'ccc'])
|
|
# insert block
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
block_db = list(query.get_blocks_status_from_transaction(conn,
|
|
create_tx.id))
|
|
|
|
assert len(block_db) == 1
|
|
block_db = block_db.pop()
|
|
assert block_db['id'] == block.id
|
|
assert block_db['block']['voters'] == block.voters
|
|
|
|
|
|
def test_get_asset_by_id(create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create asset and block
|
|
create_tx.asset = {'msg': 'aaa'}
|
|
block = Block(transactions=[create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
asset = list(query.get_asset_by_id(conn, create_tx.id))
|
|
|
|
assert len(asset) == 1
|
|
assert asset[0]['asset'] == create_tx.asset
|
|
|
|
|
|
def test_get_spent(signed_create_tx, signed_transfer_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert two blocks, one for the create and one for the
|
|
# transfer transaction
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
block = Block(transactions=[signed_transfer_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
spents = list(query.get_spent(conn, signed_create_tx.id, 0))
|
|
|
|
assert len(spents) == 1
|
|
assert spents[0] == signed_transfer_tx.to_dict()
|
|
|
|
|
|
def test_get_spent_for_tx_with_multiple_inputs(carol):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block, Transaction
|
|
conn = connect()
|
|
tx_0 = Transaction.create(
|
|
[carol.public_key],
|
|
[([carol.public_key], 1),
|
|
([carol.public_key], 1),
|
|
([carol.public_key], 2)],
|
|
).sign([carol.private_key])
|
|
block = Block(transactions=[tx_0])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
spents = list(query.get_spent(conn, tx_0.id, 0))
|
|
assert not spents
|
|
|
|
tx_1 = Transaction.transfer(
|
|
tx_0.to_inputs()[2:3],
|
|
[([carol.public_key], 1),
|
|
([carol.public_key], 1)],
|
|
asset_id=tx_0.id,
|
|
).sign([carol.private_key])
|
|
block = Block(transactions=[tx_1])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
spents = list(query.get_spent(conn, tx_0.id, 0))
|
|
assert not spents
|
|
|
|
tx_2 = Transaction.transfer(
|
|
tx_0.to_inputs()[0:1] + tx_1.to_inputs()[1:2],
|
|
[([carol.public_key], 2)],
|
|
asset_id=tx_0.id,
|
|
).sign([carol.private_key])
|
|
block = Block(transactions=[tx_2])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
spents = list(query.get_spent(conn, tx_0.id, 1))
|
|
assert not spents
|
|
|
|
|
|
def test_get_owned_ids(signed_create_tx, user_pk):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert a block
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
owned_ids = list(query.get_owned_ids(conn, user_pk))
|
|
|
|
assert len(owned_ids) == 1
|
|
assert owned_ids[0] == signed_create_tx.to_dict()
|
|
|
|
|
|
def test_get_votes_by_block_id(signed_create_tx, structurally_valid_vote):
|
|
from bigchaindb.common.crypto import generate_key_pair
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert a block
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
# create and insert some votes
|
|
structurally_valid_vote['vote']['voting_for_block'] = block.id
|
|
conn.db.votes.insert_one(structurally_valid_vote)
|
|
# create a second vote under a different key
|
|
_, pk = generate_key_pair()
|
|
structurally_valid_vote['vote']['voting_for_block'] = block.id
|
|
structurally_valid_vote['node_pubkey'] = pk
|
|
structurally_valid_vote.pop('_id')
|
|
conn.db.votes.insert_one(structurally_valid_vote)
|
|
|
|
votes = list(query.get_votes_by_block_id(conn, block.id))
|
|
|
|
assert len(votes) == 2
|
|
assert votes[0]['vote']['voting_for_block'] == block.id
|
|
assert votes[1]['vote']['voting_for_block'] == block.id
|
|
|
|
|
|
def test_get_votes_by_block_id_and_voter(signed_create_tx,
|
|
structurally_valid_vote):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert a block
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
# create and insert some votes
|
|
structurally_valid_vote['vote']['voting_for_block'] = block.id
|
|
structurally_valid_vote['node_pubkey'] = 'aaa'
|
|
conn.db.votes.insert_one(structurally_valid_vote)
|
|
structurally_valid_vote['vote']['voting_for_block'] = block.id
|
|
structurally_valid_vote['node_pubkey'] = 'bbb'
|
|
structurally_valid_vote.pop('_id')
|
|
conn.db.votes.insert_one(structurally_valid_vote)
|
|
|
|
votes = list(query.get_votes_by_block_id_and_voter(conn, block.id, 'aaa'))
|
|
|
|
assert len(votes) == 1
|
|
assert votes[0]['node_pubkey'] == 'aaa'
|
|
|
|
|
|
def test_write_block(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and write block
|
|
block = Block(transactions=[signed_create_tx])
|
|
query.write_block(conn, block.to_dict())
|
|
|
|
block_db = conn.db.bigchain.find_one({'id': block.id}, {'_id': False})
|
|
|
|
assert block_db == block.to_dict()
|
|
|
|
|
|
def test_get_block(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert block
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
block_db = query.get_block(conn, block.id)
|
|
|
|
assert block_db == block.to_dict()
|
|
|
|
|
|
def test_count_blocks(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert some blocks
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
assert query.count_blocks(conn) == 2
|
|
|
|
|
|
def test_count_backlog(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# create and insert some transations
|
|
conn.db.backlog.insert_one(signed_create_tx.to_dict())
|
|
signed_create_tx.metadata = {'msg': 'aaa'}
|
|
conn.db.backlog.insert_one(signed_create_tx.to_dict())
|
|
|
|
assert query.count_backlog(conn) == 2
|
|
|
|
|
|
def test_write_vote(structurally_valid_vote):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
# write a vote
|
|
query.write_vote(conn, structurally_valid_vote)
|
|
# retrieve the vote
|
|
vote_db = conn.db.votes.find_one(
|
|
{'node_pubkey': structurally_valid_vote['node_pubkey']},
|
|
{'_id': False}
|
|
)
|
|
|
|
assert vote_db == structurally_valid_vote
|
|
|
|
|
|
def test_duplicate_vote_raises_duplicate_key(structurally_valid_vote):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.backend.exceptions import DuplicateKeyError
|
|
conn = connect()
|
|
|
|
# write a vote
|
|
query.write_vote(conn, structurally_valid_vote)
|
|
|
|
# write the same vote a second time
|
|
with pytest.raises(DuplicateKeyError):
|
|
query.write_vote(conn, structurally_valid_vote)
|
|
|
|
|
|
def test_get_genesis_block(genesis_block):
|
|
from bigchaindb.backend import connect, query
|
|
conn = connect()
|
|
|
|
assets, genesis_block_dict = genesis_block.decouple_assets()
|
|
assert query.get_genesis_block(conn) == genesis_block_dict
|
|
|
|
|
|
def test_get_last_voted_block_id(genesis_block, signed_create_tx, b):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
from bigchaindb.common.exceptions import CyclicBlockchainError
|
|
conn = connect()
|
|
|
|
# check that the last voted block is the genesis block
|
|
assert query.get_last_voted_block_id(conn, b.me) == genesis_block.id
|
|
|
|
# create and insert a new vote and block
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
vote = b.vote(block.id, genesis_block.id, True)
|
|
conn.db.votes.insert_one(vote)
|
|
|
|
assert query.get_last_voted_block_id(conn, b.me) == block.id
|
|
|
|
# force a bad chain
|
|
vote.pop('_id')
|
|
vote['vote']['voting_for_block'] = genesis_block.id
|
|
vote['vote']['previous_block'] = block.id
|
|
conn.db.votes.insert_one(vote)
|
|
|
|
with pytest.raises(CyclicBlockchainError):
|
|
query.get_last_voted_block_id(conn, b.me)
|
|
|
|
|
|
def test_get_unvoted_blocks(signed_create_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block
|
|
conn = connect()
|
|
|
|
# create and insert a block
|
|
block = Block(transactions=[signed_create_tx], node_pubkey='aaa')
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
unvoted_blocks = list(query.get_unvoted_blocks(conn, 'aaa'))
|
|
|
|
assert len(unvoted_blocks) == 1
|
|
assert unvoted_blocks[0] == block.to_dict()
|
|
|
|
|
|
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
|
from bigchaindb.backend import connect, query
|
|
from bigchaindb.models import Block, Transaction
|
|
conn = connect()
|
|
|
|
# create and insert two blocks, one for the create and one for the
|
|
# transfer transaction
|
|
block = Block(transactions=[signed_create_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
block = Block(transactions=[signed_transfer_tx])
|
|
conn.db.bigchain.insert_one(block.to_dict())
|
|
|
|
asset_id = Transaction.get_asset_id([signed_create_tx, signed_transfer_tx])
|
|
|
|
# Test get by just asset id
|
|
txids = set(query.get_txids_filtered(conn, asset_id))
|
|
assert txids == {signed_create_tx.id, signed_transfer_tx.id}
|
|
|
|
# Test get by asset and CREATE
|
|
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.CREATE))
|
|
assert txids == {signed_create_tx.id}
|
|
|
|
# Test get by asset and TRANSFER
|
|
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.TRANSFER))
|
|
assert txids == {signed_transfer_tx.id}
|