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()) [(block_id, tx)] = list(query.get_owned_ids(conn, user_pk)) assert block_id == block.id assert tx == 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) 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() assert query.get_genesis_block(conn) == genesis_block.to_dict() def test_get_last_voted_block(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(conn, b.me) == genesis_block.to_dict() # 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(conn, b.me) == block.to_dict() # 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(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} def test_get_spending_transactions(user_pk): from bigchaindb.backend import connect, query from bigchaindb.models import Block, Transaction conn = connect() out = [([user_pk], 1)] tx1 = Transaction.create([user_pk], out * 3) inputs = tx1.to_inputs() tx2 = Transaction.transfer([inputs[0]], out, tx1.id) tx3 = Transaction.transfer([inputs[1]], out, tx1.id) tx4 = Transaction.transfer([inputs[2]], out, tx1.id) block = Block([tx1, tx2, tx3, tx4]) conn.db.bigchain.insert_one(block.to_dict()) links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()] res = list(query.get_spending_transactions(conn, links)) # tx3 not a member because input 1 not asked for assert res == [(block.id, tx2.to_dict()), (block.id, tx4.to_dict())] def test_get_votes_for_blocks_by_voter(): from bigchaindb.backend import connect, query conn = connect() votes = [ { 'node_pubkey': 'a', 'vote': {'voting_for_block': 'block1'}, }, { 'node_pubkey': 'b', 'vote': {'voting_for_block': 'block1'}, }, { 'node_pubkey': 'a', 'vote': {'voting_for_block': 'block2'}, }, { 'node_pubkey': 'a', 'vote': {'voting_for_block': 'block3'}, } ] for vote in votes: conn.db.votes.insert_one(vote.copy()) res = query.get_votes_for_blocks_by_voter(conn, ['block1', 'block2'], 'a') assert list(res) == [votes[0], votes[2]]