def test_get_spent_with_double_spend_detected(self, b, alice): from bigchaindb.models import Transaction from bigchaindb.common.exceptions import DoubleSpend from bigchaindb.exceptions import CriticalDoubleSpend tx = Transaction.create([alice.public_key], [([alice.public_key], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) transfer_tx = Transaction.transfer(tx.to_inputs(), [([alice.public_key], 1)], asset_id=tx.id) transfer_tx = transfer_tx.sign([alice.private_key]) transfer_tx2 = Transaction.transfer(tx.to_inputs(), [([alice.public_key], 2)], asset_id=tx.id) transfer_tx2 = transfer_tx2.sign([alice.private_key]) with pytest.raises(DoubleSpend): b.validate_transaction(transfer_tx2, [transfer_tx]) b.store_bulk_transactions([transfer_tx]) with pytest.raises(DoubleSpend): b.validate_transaction(transfer_tx2) b.store_bulk_transactions([transfer_tx2]) with pytest.raises(CriticalDoubleSpend): b.get_spent(tx.id, 0)
def test_post_transaction_responses(tendermint_ws_url, b): from bigchaindb.common.crypto import generate_key_pair from bigchaindb.models import Transaction alice = generate_key_pair() bob = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset=None)\ .sign([alice.private_key]) code, message = b.write_transaction(tx, 'broadcast_tx_commit') assert code == 202 tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) code, message = b.write_transaction(tx_transfer, 'broadcast_tx_commit') assert code == 202 carly = generate_key_pair() double_spend = Transaction.transfer( tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id, ).sign([alice.private_key]) for mode in ('broadcast_tx_sync', 'broadcast_tx_commit'): code, message = b.write_transaction(double_spend, mode) assert code == 500 assert message == 'Transaction validation failed'
def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from bigchaindb import backend from bigchaindb.models import Transaction from bigchaindb.common.crypto import generate_key_pair from bigchaindb.common.exceptions import DoubleSpend alice = generate_key_pair() bob = generate_key_pair() tx1 = Transaction.create([user_pk], [([alice.public_key], 3), ([user_pk], 2)], asset=None)\ .sign([user_sk]) b.store_bulk_transactions([tx1]) inputs = tx1.to_inputs() tx2 = Transaction.transfer([inputs[1]], [([user2_pk], 2)], tx1.id).sign([user_sk]) assert tx2.validate(b) tx2_dict = tx2.to_dict() fulfills = tx2_dict['inputs'][0]['fulfills'] tx2_dict['inputs'][0]['fulfills'] = {'output_index': fulfills['output_index'], 'transaction_id': fulfills['transaction_id']} backend.query.store_transactions(b.connection, [tx2_dict]) tx3 = Transaction.transfer([inputs[1]], [([bob.public_key], 2)], tx1.id).sign([user_sk]) with pytest.raises(DoubleSpend): tx3.validate(b)
def test_amount_error_transfer(alice, b, user_pk, user_sk): from bigchaindb.models import Transaction from bigchaindb.common.exceptions import AmountError # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) b.store_bulk_transactions([tx_create_signed]) # TRANSFER # output amount less than input amount tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) with pytest.raises(AmountError): tx_transfer_signed.validate(b) # TRANSFER # output amount greater than input amount tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 101)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) with pytest.raises(AmountError): tx_transfer_signed.validate(b)
def test_get_divisble_transactions_returns_500(b, client): from bigchaindb.models import Transaction from bigchaindb.common import crypto import json TX_ENDPOINT = '/api/v1/transactions' def mine(tx_list): b.store_bulk_transactions(tx_list) alice_priv, alice_pub = crypto.generate_key_pair() bob_priv, bob_pub = crypto.generate_key_pair() carly_priv, carly_pub = crypto.generate_key_pair() create_tx = Transaction.create([alice_pub], [([alice_pub], 4)]) create_tx.sign([alice_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(create_tx.to_dict())) assert res.status_code == 202 mine([create_tx]) transfer_tx = Transaction.transfer(create_tx.to_inputs(), [([alice_pub], 3), ([bob_pub], 1)], asset_id=create_tx.id) transfer_tx.sign([alice_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict())) assert res.status_code == 202 mine([transfer_tx]) transfer_tx_carly = Transaction.transfer([transfer_tx.to_inputs()[1]], [([carly_pub], 1)], asset_id=create_tx.id) transfer_tx_carly.sign([bob_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx_carly.to_dict())) assert res.status_code == 202 mine([transfer_tx_carly]) asset_id = create_tx.id url = TX_ENDPOINT + '?asset_id=' + asset_id assert client.get(url).status_code == 200 assert len(client.get(url).json) == 3 url = OUTPUTS_ENDPOINT + '?public_key=' + alice_pub assert client.get(url).status_code == 200 url = OUTPUTS_ENDPOINT + '?public_key=' + bob_pub assert client.get(url).status_code == 200 url = OUTPUTS_ENDPOINT + '?public_key=' + carly_pub assert client.get(url).status_code == 200
def test_get_spent_issue_1271(b, alice, bob, carol): from bigchaindb.models import Transaction tx_1 = Transaction.create( [carol.public_key], [([carol.public_key], 8)], ).sign([carol.private_key]) assert tx_1.validate(b) b.store_bulk_transactions([tx_1]) tx_2 = Transaction.transfer( tx_1.to_inputs(), [([bob.public_key], 2), ([alice.public_key], 2), ([carol.public_key], 4)], asset_id=tx_1.id, ).sign([carol.private_key]) assert tx_2.validate(b) b.store_bulk_transactions([tx_2]) tx_3 = Transaction.transfer( tx_2.to_inputs()[2:3], [([alice.public_key], 1), ([carol.public_key], 3)], asset_id=tx_1.id, ).sign([carol.private_key]) assert tx_3.validate(b) b.store_bulk_transactions([tx_3]) tx_4 = Transaction.transfer( tx_2.to_inputs()[1:2] + tx_3.to_inputs()[0:1], [([bob.public_key], 3)], asset_id=tx_1.id, ).sign([alice.private_key]) assert tx_4.validate(b) b.store_bulk_transactions([tx_4]) tx_5 = Transaction.transfer( tx_2.to_inputs()[0:1], [([alice.public_key], 2)], asset_id=tx_1.id, ).sign([bob.private_key]) assert tx_5.validate(b) b.store_bulk_transactions([tx_5]) assert b.get_spent(tx_2.id, 0) == tx_5 assert not b.get_spent(tx_5.id, 0) assert b.get_outputs_filtered(alice.public_key) assert b.get_outputs_filtered(alice.public_key, spent=False)
def test_get_spent_multiple_owners(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() transactions = [] for i in range(3): payload = {'somedata': i} tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)], payload) tx = tx.sign([alice.private_key]) transactions.append(tx) b.store_bulk_transactions(transactions) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) # check spents for input_tx in owned_inputs_user1: assert b.get_spent(input_tx.txid, input_tx.output) is None # create a transaction tx = Transaction.transfer(transactions[0].to_inputs(), [([user3_pk], 1)], asset_id=transactions[0].id) tx = tx.sign([user_sk, user2_sk]) b.store_bulk_transactions([tx]) # check that used inputs are marked as spent assert b.get_spent(transactions[0].id, 0) == tx # check that the other remain marked as unspent for unspent in transactions[1:]: assert b.get_spent(unspent.id, 0) is None
def test_cant_spend_same_input_twice_in_tx(b, genesis_block, alice): """Recreate duplicated fulfillments bug https://github.com/bigchaindb/bigchaindb/issues/1099 """ from bigchaindb.models import Transaction from bigchaindb.common.exceptions import DoubleSpend # create a divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key], 100)]) tx_create_signed = tx_create.sign([alice.private_key]) assert b.validate_transaction(tx_create_signed) == tx_create_signed # create a block and valid vote block = b.create_block([tx_create_signed]) b.write_block(block) vote = b.vote(block.id, genesis_block.id, True) b.write_vote(vote) # Create a transfer transaction with duplicated fulfillments dup_inputs = tx_create.to_inputs() + tx_create.to_inputs() tx_transfer = Transaction.transfer(dup_inputs, [([alice.public_key], 200)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key]) with pytest.raises(DoubleSpend): tx_transfer_signed.validate(b)
def test_get_owned_ids_multiple_owners(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.common.transaction import TransactionLink from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user_pk) expected_owned_inputs_user1 = [TransactionLink(tx.id, 0)] assert owned_inputs_user1 == owned_inputs_user2 assert owned_inputs_user1 == expected_owned_inputs_user1 tx = Transaction.transfer(tx.to_inputs(), [([user3_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk, user2_sk]) b.store_bulk_transactions([tx]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user2_pk) spent_user1 = b.get_spent(tx.id, 0) assert owned_inputs_user1 == owned_inputs_user2 assert not spent_user1
def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.common.transaction import TransactionLink from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user2_pk) assert owned_inputs_user1 == [TransactionLink(tx.id, 0)] assert owned_inputs_user2 == [] tx_transfer = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx_transfer = tx_transfer.sign([user_sk]) b.store_bulk_transactions([tx_transfer]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user2_pk) assert owned_inputs_user1 == [TransactionLink(tx.id, 0)] assert owned_inputs_user2 == [TransactionLink(tx_transfer.id, 0)]
def test_read_transaction_invalid_block_and_backlog(self, b, user_pk, user_sk): from bigchaindb.models import Transaction input_tx = b.get_owned_ids(user_pk).pop() input_tx = b.get_transaction(input_tx.txid) inputs = input_tx.to_inputs() tx = Transaction.transfer(inputs, [([user_pk], 1)], asset_id=input_tx.id) tx = tx.sign([user_sk]) # Make sure there's a copy of tx in the backlog b.write_transaction(tx) # create block block = b.create_block([tx]) b.write_block(block) # vote the block invalid vote = b.vote(block.id, b.get_last_voted_block().id, False) b.write_vote(vote) # a copy of the tx is both in the backlog and in an invalid # block, so get_transaction should return a transaction, # and a status of TX_IN_BACKLOG response, status = b.get_transaction(tx.id, include_status=True) assert tx.to_dict() == response.to_dict() assert status == b.TX_IN_BACKLOG
def test_get_asset_id_transfer_transaction(b, signed_create_tx, user_pk): from bigchaindb.models import Transaction tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) asset_id = Transaction.get_asset_id(tx_transfer) assert asset_id == tx_transfer.asset['id']
def test_multiple_owners_before_multiple_owners_after_single_input( self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() user4_sk, user4_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) # get input tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() tx_input = b.get_transaction(tx_link.txid) tx = Transaction.transfer(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_id=tx_input.id) tx = tx.sign([user_sk, user2_sk]) tx.validate(b) assert len(tx.inputs) == 1 assert len(tx.outputs) == 1
def test_multiple_owners_before_multiple_owners_after_single_input(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() user4_sk, user4_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) # get input tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() tx_input = b.get_transaction(tx_link.txid) tx = Transaction.transfer(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_id=tx_input.id) tx = tx.sign([user_sk, user2_sk]) tx.validate(b) assert len(tx.inputs) == 1 assert len(tx.outputs) == 1
def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) block = b.create_block([tx]) b.write_block(block) owned_inputs_user1 = b.get_owned_ids(user_pk).pop() # check spents input_txid = owned_inputs_user1.txid input_idx = owned_inputs_user1.output spent_inputs_user1 = b.get_spent(input_txid, input_idx) assert spent_inputs_user1 is None # create a transaction and block tx = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk]) block = b.create_block([tx]) b.write_block(block) spent_inputs_user1 = b.get_spent(input_txid, input_idx) assert spent_inputs_user1 == tx
def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(b, user_pk, user_sk): from bigchaindb.models import Transaction from bigchaindb.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([b.me], [([user_pk], 50), ([user_pk, b.me], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([b.me_private]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([b.me], 50), ([b.me, user_pk], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk]) b.store_bulk_transactions([tx_create_signed, tx_transfer_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert len(tx_transfer_signed.outputs) == 2 assert tx_transfer_signed.outputs[0].amount == 50 assert tx_transfer_signed.outputs[1].amount == 50 assert len(tx_transfer_signed.inputs) == 2 cond_cid0 = tx_transfer_signed.outputs[0].to_dict() cond_cid1 = tx_transfer_signed.outputs[1].to_dict() assert 'subconditions' not in cond_cid0['condition']['details'] assert 'subconditions' in cond_cid1['condition']['details'] assert len(cond_cid1['condition']['details']['subconditions']) == 2 ffill_fid0 = _fulfillment_to_details(tx_transfer_signed.inputs[0].fulfillment) ffill_fid1 = _fulfillment_to_details(tx_transfer_signed.inputs[1].fulfillment) assert 'subconditions' not in ffill_fid0 assert 'subconditions' in ffill_fid1 assert len(ffill_fid1['subconditions']) == 2
def test_single_in_multiple_own_single_out_single_own_transfer(b, user_pk, user_sk): from bigchaindb.models import Transaction from bigchaindb.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([b.me], [([b.me, user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([b.me_private]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([b.me], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([b.me_private, user_sk]) b.store_bulk_transactions([tx_create_signed, tx_transfer_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert len(tx_transfer_signed.outputs) == 1 assert tx_transfer_signed.outputs[0].amount == 100 assert len(tx_transfer_signed.inputs) == 1 ffill = _fulfillment_to_details(tx_transfer_signed.inputs[0].fulfillment) assert 'subconditions' in ffill assert len(ffill['subconditions']) == 2
def test_single_in_single_own_single_out_multiple_own_transfer(b, user_pk, user_sk): from bigchaindb.models import Transaction # CREATE divisible asset tx_create = Transaction.create([b.me], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([b.me_private]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([b.me, b.me], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) b.store_bulk_transactions([tx_create_signed, tx_transfer_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert len(tx_transfer_signed.outputs) == 1 assert tx_transfer_signed.outputs[0].amount == 100 condition = tx_transfer_signed.outputs[0].to_dict() assert 'subconditions' in condition['condition']['details'] assert len(condition['condition']['details']['subconditions']) == 2 assert len(tx_transfer_signed.inputs) == 1
def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk).pop() # check spents input_txid = owned_inputs_user1.txid spent_inputs_user1 = b.get_spent(input_txid, 0) assert spent_inputs_user1 is None # create a transaction and send it tx = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk]) b.store_bulk_transactions([tx]) spent_inputs_user1 = b.get_spent(input_txid, 0) assert spent_inputs_user1 == tx
def test_post_wrong_asset_division_transfer_returns_400(b, client, user_pk): from bigchaindb.models import Transaction from bigchaindb.common.exceptions import AmountError priv_key, pub_key = crypto.generate_key_pair() create_tx = Transaction.create([pub_key], [([pub_key], 10)], asset={ 'test': 'asset' }).sign([priv_key]) res = client.post(TX_ENDPOINT + '?mode=commit', data=json.dumps(create_tx.to_dict())) assert res.status_code == 202 transfer_tx = Transaction.transfer( create_tx.to_inputs(), [([pub_key], 20)], # 20 > 10 asset_id=create_tx.id).sign([priv_key]) res = client.post(TX_ENDPOINT + '?mode=commit', data=json.dumps(transfer_tx.to_dict())) expected_error_message = \ f'Invalid transaction ({AmountError.__name__}): ' + \ 'The amount used in the inputs `10` needs to be same as the amount used in the outputs `20`' assert res.status_code == 400 assert res.json['message'] == expected_error_message
def test_threshold_same_public_key(alice, b, user_pk, user_sk): # If we try to fulfill a threshold condition where each subcondition has # the same key get_subcondition_from_vk will always return the first # subcondition. This means that only the 1st subfulfillment will be # generated # Creating threshold conditions with the same key does not make sense but # that does not mean that the code shouldn't work. from bigchaindb.models import Transaction # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk, user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk, user_sk]) b.store_bulk_transactions([tx_create_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed b.store_bulk_transactions([tx_transfer_signed]) with pytest.raises(DoubleSpend): tx_transfer_signed.validate(b)
def test_get_owned_ids_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.common.transaction import TransactionLink from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() # create divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 1), ([user_pk], 1)]) tx_create_signed = tx_create.sign([alice.private_key]) b.store_bulk_transactions([tx_create_signed]) # get input owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user2_pk) expected_owned_inputs_user1 = [TransactionLink(tx_create.id, 0), TransactionLink(tx_create.id, 1)] assert owned_inputs_user1 == expected_owned_inputs_user1 assert owned_inputs_user2 == [] # transfer divisible asset divided in two outputs tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([user2_pk], 1), ([user2_pk], 1)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) b.store_bulk_transactions([tx_transfer_signed]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key(user_pk) owned_inputs_user2 = b.fastquery.get_outputs_by_public_key(user2_pk) assert owned_inputs_user1 == expected_owned_inputs_user1 assert owned_inputs_user2 == [TransactionLink(tx_transfer.id, 0), TransactionLink(tx_transfer.id, 1)]
def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): from bigchaindb.models import Transaction from bigchaindb.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk]) b.store_bulk_transactions([tx_create_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert len(tx_transfer_signed.outputs) == 1 assert tx_transfer_signed.outputs[0].amount == 100 assert len(tx_transfer_signed.inputs) == 2 ffill_fid0 = _fulfillment_to_details(tx_transfer_signed.inputs[0].fulfillment) ffill_fid1 = _fulfillment_to_details(tx_transfer_signed.inputs[1].fulfillment) assert 'subconditions' not in ffill_fid0 assert 'subconditions' in ffill_fid1 assert len(ffill_fid1['subconditions']) == 2 b.store_bulk_transactions([tx_transfer_signed]) with pytest.raises(DoubleSpend): tx_transfer_signed.validate(b)
def test_multiple_owners_before_multiple_owners_after_single_input(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() user4_sk, user4_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) block = b.create_block([tx]) b.write_block(block) # vote block valid vote = b.vote(block.id, b.get_last_voted_block().id, True) b.write_vote(vote) # get input tx_link = b.get_owned_ids(user_pk).pop() tx_input = b.get_transaction(tx_link.txid) tx = Transaction.transfer(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_id=tx_input.id) tx = tx.sign([user_sk, user2_sk]) tx.validate(b) assert len(tx.inputs) == 1 assert len(tx.outputs) == 1
def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): from bigchaindb.models import Transaction # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 50), ([alice.public_key, alice.public_key], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) b.store_bulk_transactions([tx_create_signed]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert len(tx_transfer_signed.outputs) == 2 assert tx_transfer_signed.outputs[0].amount == 50 assert tx_transfer_signed.outputs[1].amount == 50 output_cid1 = tx_transfer_signed.outputs[1].to_dict() assert 'subconditions' in output_cid1['condition']['details'] assert len(output_cid1['condition']['details']['subconditions']) == 2 assert len(tx_transfer_signed.inputs) == 1 b.store_bulk_transactions([tx_transfer_signed]) with pytest.raises(DoubleSpend): tx_transfer_signed.validate(b)
def test_get_owned_ids_multiple_owners(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.common.transaction import TransactionLink from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) block = b.create_block([tx]) b.write_block(block) owned_inputs_user1 = b.get_owned_ids(user_pk) owned_inputs_user2 = b.get_owned_ids(user2_pk) expected_owned_inputs_user1 = [TransactionLink(tx.id, 0)] assert owned_inputs_user1 == owned_inputs_user2 assert owned_inputs_user1 == expected_owned_inputs_user1 tx = Transaction.transfer(tx.to_inputs(), [([user3_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk, user2_sk]) block = b.create_block([tx]) b.write_block(block) owned_inputs_user1 = b.get_owned_ids(user_pk) owned_inputs_user2 = b.get_owned_ids(user2_pk) assert owned_inputs_user1 == owned_inputs_user2 assert owned_inputs_user1 == []
def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() tx = Transaction.create([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) owned_inputs_user1 = b.fastquery.get_outputs_by_public_key( user_pk).pop() # check spents input_txid = owned_inputs_user1.txid spent_inputs_user1 = b.get_spent(input_txid, 0) assert spent_inputs_user1 is None # create a transaction and send it tx = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk]) b.store_bulk_transactions([tx]) spent_inputs_user1 = b.get_spent(input_txid, 0) assert spent_inputs_user1 == tx
def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): from bigchaindb.models import Transaction from bigchaindb.exceptions import CriticalDoubleSpend from bigchaindb.common.exceptions import DoubleSpend asset = {'test': 'asset'} tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) double_spend = Transaction.transfer(tx.to_inputs(), [([carol.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) same_input_double_spend = Transaction.transfer(tx.to_inputs() + tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) b.store_bulk_transactions([tx]) with pytest.raises(DoubleSpend): same_input_double_spend.validate(b) assert b.get_spent(tx.id, tx_transfer.inputs[0].fulfills.output, [tx_transfer]) with pytest.raises(DoubleSpend): b.get_spent(tx.id, tx_transfer.inputs[0].fulfills.output, [tx_transfer, double_spend]) b.store_bulk_transactions([tx_transfer]) with pytest.raises(DoubleSpend): b.get_spent(tx.id, tx_transfer.inputs[0].fulfills.output, [double_spend]) b.store_bulk_transactions([double_spend]) with pytest.raises(CriticalDoubleSpend): b.get_spent(tx.id, tx_transfer.inputs[0].fulfills.output)
def test_get_spent_issue_1271(b, alice, bob, carol): from bigchaindb.models import Transaction tx_1 = Transaction.create( [carol.public_key], [([carol.public_key], 8)], ).sign([carol.private_key]) assert b.validate_transaction(tx_1) b.store_bulk_transactions([tx_1]) tx_2 = Transaction.transfer( tx_1.to_inputs(), [([bob.public_key], 2), ([alice.public_key], 2), ([carol.public_key], 4)], asset_id=tx_1.id, ).sign([carol.private_key]) assert b.validate_transaction(tx_2) b.store_bulk_transactions([tx_2]) tx_3 = Transaction.transfer( tx_2.to_inputs()[2:3], [([alice.public_key], 1), ([carol.public_key], 3)], asset_id=tx_1.id, ).sign([carol.private_key]) assert b.validate_transaction(tx_3) b.store_bulk_transactions([tx_3]) tx_4 = Transaction.transfer( tx_2.to_inputs()[1:2] + tx_3.to_inputs()[0:1], [([bob.public_key], 3)], asset_id=tx_1.id, ).sign([alice.private_key]) assert b.validate_transaction(tx_4) b.store_bulk_transactions([tx_4]) tx_5 = Transaction.transfer( tx_2.to_inputs()[0:1], [([alice.public_key], 2)], asset_id=tx_1.id, ).sign([bob.private_key]) assert b.validate_transaction(tx_5) b.store_bulk_transactions([tx_5]) assert b.get_spent(tx_2.id, 0) == tx_5 assert not b.get_spent(tx_5.id, 0) assert b.get_outputs_filtered(alice.public_key) assert b.get_outputs_filtered(alice.public_key, spent=False)
def txlist(b, user_pk, user2_pk, user_sk, user2_sk, genesis_block): from bigchaindb.models import Transaction prev_block_id = genesis_block.id # Create first block with CREATE transactions create1 = Transaction.create([user_pk], [([user2_pk], 6)]) \ .sign([user_sk]) create2 = Transaction.create([user2_pk], [([user2_pk], 5), ([user_pk], 5)]) \ .sign([user2_sk]) block1 = b.create_block([create1, create2]) b.write_block(block1) # Create second block with TRANSFER transactions transfer1 = Transaction.transfer(create1.to_inputs(), [([user_pk], 8)], create1.id).sign([user2_sk]) block2 = b.create_block([transfer1]) b.write_block(block2) # Create block with double spend tx_doublespend = Transaction.transfer(create1.to_inputs(), [([user_pk], 9)], create1.id).sign([user2_sk]) block_doublespend = b.create_block([tx_doublespend]) b.write_block(block_doublespend) # Vote on all the blocks prev_block_id = genesis_block.id for bid in [block1.id, block2.id]: vote = b.vote(bid, prev_block_id, True) prev_block_id = bid b.write_vote(vote) # Create undecided block untx = Transaction.create([user_pk], [([user2_pk], 7)]) \ .sign([user_sk]) block_undecided = b.create_block([untx]) b.write_block(block_undecided) return type('', (), { 'create1': create1, 'transfer1': transfer1, })
def generate_create_and_transfer(keypair=None): if not keypair: keypair = generate_key_pair() priv_key, pub_key = keypair create_tx = Transaction.create([pub_key], [([pub_key], 10)]).sign([priv_key]) transfer_tx = Transaction.transfer( create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) return create_tx, transfer_tx
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_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): from bigchaindb import App from bigchaindb.models import Transaction from bigchaindb.common.crypto import generate_key_pair app = App(a, b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() app.begin_block(begin_block) alice = generate_key_pair() bob = generate_key_pair() carly = generate_key_pair() asset = { 'msg': 'live long and prosper' } tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeOk tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) assert result.code == CodeTypeOk double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(double_spend)) assert result.code == CodeTypeError
def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from bigchaindb import App from bigchaindb.models import Transaction from bigchaindb.common.crypto import generate_key_pair app = App(b) app.init_chain(init_chain_request) begin_block = RequestBeginBlock() app.begin_block(begin_block) alice = generate_key_pair() bob = generate_key_pair() carly = generate_key_pair() asset = { 'msg': 'live long and prosper' } tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeOk tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) assert result.code == CodeTypeOk double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(double_spend)) assert result.code == CodeTypeError
def test_get_spending_transactions(user_pk, user_sk): from bigchaindb.backend import connect, query from bigchaindb.models import Transaction conn = connect() out = [([user_pk], 1)] tx1 = Transaction.create([user_pk], out * 3) tx1.sign([user_sk]) 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) txns = [tx.to_dict() for tx in [tx1, tx2, tx3, tx4]] conn.db.transactions.insert_many(txns) links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()] txns = list(query.get_spending_transactions(conn, links)) # tx3 not a member because input 1 not asked for assert txns == [tx2.to_dict(), tx4.to_dict()]
def test_validation_with_transaction_buffer(b): from bigchaindb.common.crypto import generate_key_pair from bigchaindb.models import Transaction priv_key, pub_key = generate_key_pair() create_tx = Transaction.create([pub_key], [([pub_key], 10)]).sign([priv_key]) transfer_tx = Transaction.transfer(create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) double_spend = Transaction.transfer(create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) assert b.is_valid_transaction(create_tx) assert b.is_valid_transaction(transfer_tx, [create_tx]) assert not b.is_valid_transaction(create_tx, [create_tx]) assert not b.is_valid_transaction(transfer_tx, [create_tx, transfer_tx]) assert not b.is_valid_transaction(double_spend, [create_tx, transfer_tx])
def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): from bigchaindb.models import Transaction tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) tx_transfer_signed = tx_transfer.sign([user_sk]) b.store_bulk_transactions([signed_create_tx]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.asset['id'] == signed_create_tx.id
def test_get_spending_transactions(user_pk, user_sk): from bigchaindb.backend import connect, query from bigchaindb.models import Transaction conn = connect() out = [([user_pk], 1)] tx1 = Transaction.create([user_pk], out * 3) tx1.sign([user_sk]) inputs = tx1.to_inputs() tx2 = Transaction.transfer([inputs[0]], out, tx1.id).sign([user_sk]) tx3 = Transaction.transfer([inputs[1]], out, tx1.id).sign([user_sk]) tx4 = Transaction.transfer([inputs[2]], out, tx1.id).sign([user_sk]) txns = [deepcopy(tx.to_dict()) for tx in [tx1, tx2, tx3, tx4]] conn.db.transactions.insert_many(txns) links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()] txns = list(query.get_spending_transactions(conn, links)) # tx3 not a member because input 1 not asked for assert txns == [tx2.to_dict(), tx4.to_dict()]
def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): from bigchaindb.models import Transaction # CREATE divisible asset # `b` creates a divisible asset and assigns 50 shares to `b` and # 50 shares to `user_pk` tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER divisible asset # `b` transfers its 50 shares to `user_pk` # after this transaction `user_pk` will have a total of 100 shares # split across two different transactions tx_transfer1 = Transaction.transfer(tx_create.to_inputs([1]), [([user_pk], 50)], asset_id=tx_create.id) tx_transfer1_signed = tx_transfer1.sign([alice.private_key]) # TRANSFER # `user_pk` combines two different transaction with 50 shares each and # transfers a total of 100 shares back to `b` tx_transfer2 = Transaction.transfer(tx_create.to_inputs([0]) + tx_transfer1.to_inputs([0]), [([alice.private_key], 100)], asset_id=tx_create.id) tx_transfer2_signed = tx_transfer2.sign([user_sk]) b.store_bulk_transactions( [tx_create_signed, tx_transfer1_signed, tx_transfer2_signed]) assert tx_transfer2_signed.validate(b) == tx_transfer2_signed assert len(tx_transfer2_signed.outputs) == 1 assert tx_transfer2_signed.outputs[0].amount == 100 assert len(tx_transfer2_signed.inputs) == 2 fid0_input = tx_transfer2_signed.inputs[0].fulfills.txid fid1_input = tx_transfer2_signed.inputs[1].fulfills.txid assert fid0_input == tx_create.id assert fid1_input == tx_transfer1.id
def test_get_spending_transactions_multiple_inputs(): from bigchaindb.backend import connect, query from bigchaindb.models import Transaction from bigchaindb.common.crypto import generate_key_pair conn = connect() (alice_sk, alice_pk) = generate_key_pair() (bob_sk, bob_pk) = generate_key_pair() (carol_sk, carol_pk) = generate_key_pair() out = [([alice_pk], 9)] tx1 = Transaction.create([alice_pk], out).sign([alice_sk]) inputs1 = tx1.to_inputs() tx2 = Transaction.transfer([inputs1[0]], [([alice_pk], 6), ([bob_pk], 3)], tx1.id).sign([alice_sk]) inputs2 = tx2.to_inputs() tx3 = Transaction.transfer([inputs2[0]], [([bob_pk], 3), ([carol_pk], 3)], tx1.id).sign([alice_sk]) inputs3 = tx3.to_inputs() tx4 = Transaction.transfer([inputs2[1], inputs3[0]], [([carol_pk], 6)], tx1.id).sign([bob_sk]) txns = [deepcopy(tx.to_dict()) for tx in [tx1, tx2, tx3, tx4]] conn.db.transactions.insert_many(txns) links = [ ({'transaction_id': tx2.id, 'output_index': 0}, 1, [tx3.id]), ({'transaction_id': tx2.id, 'output_index': 1}, 1, [tx4.id]), ({'transaction_id': tx3.id, 'output_index': 0}, 1, [tx4.id]), ({'transaction_id': tx3.id, 'output_index': 1}, 0, None), ] for l, num, match in links: txns = list(query.get_spending_transactions(conn, [l])) assert len(txns) == num if len(txns): assert [tx['id'] for tx in txns] == match
def test_asset_transfer(b, user_pk, user_sk): from bigchaindb.models import Transaction tx_input = b.get_owned_ids(user_pk).pop() tx_create = b.get_transaction(tx_input.txid) tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([user_pk], 1)], tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) assert tx_transfer_signed.validate(b) == tx_transfer_signed assert tx_transfer_signed.asset['id'] == tx_create.id
def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): from bigchaindb.models import Transaction # CREATE divisible asset # `b` creates a divisible asset and assigns 50 shares to `b` and # 50 shares to `user_pk` tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER divisible asset # `b` transfers its 50 shares to `user_pk` # after this transaction `user_pk` will have a total of 100 shares # split across two different transactions tx_transfer1 = Transaction.transfer(tx_create.to_inputs([1]), [([user_pk], 50)], asset_id=tx_create.id) tx_transfer1_signed = tx_transfer1.sign([alice.private_key]) # TRANSFER # `user_pk` combines two different transaction with 50 shares each and # transfers a total of 100 shares back to `b` tx_transfer2 = Transaction.transfer(tx_create.to_inputs([0]) + tx_transfer1.to_inputs([0]), [([alice.private_key], 100)], asset_id=tx_create.id) tx_transfer2_signed = tx_transfer2.sign([user_sk]) b.store_bulk_transactions([tx_create_signed, tx_transfer1_signed]) assert tx_transfer2_signed.validate(b) == tx_transfer2_signed assert len(tx_transfer2_signed.outputs) == 1 assert tx_transfer2_signed.outputs[0].amount == 100 assert len(tx_transfer2_signed.inputs) == 2 fid0_input = tx_transfer2_signed.inputs[0].fulfills.txid fid1_input = tx_transfer2_signed.inputs[1].fulfills.txid assert fid0_input == tx_create.id assert fid1_input == tx_transfer1.id
def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk): from bigchaindb.common.exceptions import AssetIdMismatch from bigchaindb.models import Transaction tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) tx_transfer.asset['id'] = 'a' * 64 tx_transfer_signed = tx_transfer.sign([user_sk]) b.store_bulk_transactions([signed_create_tx]) with pytest.raises(AssetIdMismatch): tx_transfer_signed.validate(b)
def test_non_create_input_not_found(self, b, user_pk): from cryptoconditions import Ed25519Sha256 from bigchaindb.common.exceptions import InputDoesNotExist from bigchaindb.common.transaction import Input, TransactionLink from bigchaindb.models import Transaction # Create an input for a non existing transaction input = Input(Ed25519Sha256(public_key=b58decode(user_pk)), [user_pk], TransactionLink('somethingsomething', 0)) tx = Transaction.transfer([input], [([user_pk], 1)], asset_id='mock_asset_link') with pytest.raises(InputDoesNotExist): tx.validate(b)
def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_create_tx): from bigchaindb.models import Transaction transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id) transfer_tx = transfer_tx.sign([user_sk]) res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict())) assert res.status_code == 202 assert res.json['inputs'][0]['owners_before'][0] == user_pk assert res.json['outputs'][0]['public_keys'][0] == user_pk
def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_create_tx): from bigchaindb.models import Transaction from bigchaindb.common.exceptions import InvalidSignature transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id) transfer_tx._hash() res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict())) expected_status_code = 400 expected_error_message = 'Invalid transaction ({}): {}'.format( InvalidSignature.__name__, 'Transaction signature is invalid.') assert res.status_code == expected_status_code assert res.json['message'] == expected_error_message
def test_transfer_single_owner_single_input(self, b, inputs, user_pk, user_sk): from bigchaindb.common import crypto from bigchaindb.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_tx = b.get_transaction(tx_link.txid) inputs = input_tx.to_inputs() tx = Transaction.transfer(inputs, [([user2_pk], 1)], asset_id=input_tx.id) tx = tx.sign([user_sk]) # validate transaction tx.validate(b) assert len(tx.inputs) == 1 assert len(tx.outputs) == 1
def test_validation_worker_process_multiple_transactions(b): import multiprocessing as mp from bigchaindb.parallel_validation import ValidationWorker, RESET, EXIT keypair = generate_key_pair() create_tx, transfer_tx = generate_create_and_transfer(keypair) double_spend = Transaction.transfer( create_tx.to_inputs(), [([keypair.public_key], 10)], asset_id=create_tx.id).sign([keypair.private_key]) in_queue, results_queue = mp.Queue(), mp.Queue() vw = ValidationWorker(in_queue, results_queue) # Note: in the following instructions, the worker will encounter two # `RESET` messages, and an `EXIT` message. When a worker processes a # `RESET` message, it forgets all transactions it has validated. This allow # us to re-validate the same transactions. This won't happen in real life, # but it's quite handy to check if the worker actually forgot about the # past transactions (if not, it will return `False` because the # transactions look like a double spend). # `EXIT` makes the worker to stop the infinite loop. in_queue.put((0, create_tx.to_dict())) in_queue.put((10, transfer_tx.to_dict())) in_queue.put((20, double_spend.to_dict())) in_queue.put(RESET) in_queue.put((0, create_tx.to_dict())) in_queue.put((5, transfer_tx.to_dict())) in_queue.put(RESET) in_queue.put((20, create_tx.to_dict())) in_queue.put((25, double_spend.to_dict())) in_queue.put((30, transfer_tx.to_dict())) in_queue.put(EXIT) vw.run() assert results_queue.get() == (0, create_tx) assert results_queue.get() == (10, transfer_tx) assert results_queue.get() == (20, False) assert results_queue.get() == (0, create_tx) assert results_queue.get() == (5, transfer_tx) assert results_queue.get() == (20, create_tx) assert results_queue.get() == (25, double_spend) assert results_queue.get() == (30, False)