Пример #1
0
def txns(b, user_pk, user_sk, user2_pk, user2_sk):
    txs = [Transaction.create([user_pk], [([user2_pk], 1)]).sign([user_sk]),
           Transaction.create([user2_pk], [([user_pk], 1)]).sign([user2_sk]),
           Transaction.create([user_pk], [([user_pk], 1), ([user2_pk], 1)])
           .sign([user_sk])]
    b.store_bulk_transactions(txs)
    return txs
Пример #2
0
def test_get_metadata_limit_tendermint(client, b, alice):
    from bigchaindb.models import Transaction

    # create two assets
    asset1 = {'msg': 'abc 1'}
    meta1 = {'key': 'meta 1'}
    tx1 = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=meta1,
                             asset=asset1).sign([alice.private_key])
    b.store_bulk_transactions([tx1])

    asset2 = {'msg': 'abc 2'}
    meta2 = {'key': 'meta 2'}
    tx2 = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=meta2,
                             asset=asset2).sign([alice.private_key])
    b.store_bulk_transactions([tx2])

    # test that both assets are returned without limit
    res = client.get(METADATA_ENDPOINT + '?search=meta')
    assert res.status_code == 200
    assert len(res.json) == 2

    # test that only one asset is returned when using limit=1
    res = client.get(METADATA_ENDPOINT + '?search=meta&limit=1')
    assert res.status_code == 200
    assert len(res.json) == 1
Пример #3
0
def test_asset_id_mismatch(alice, user_pk):
    from bigchaindb.models import Transaction
    from bigchaindb.common.exceptions import AssetIdMismatch

    tx1 = Transaction.create([alice.public_key], [([user_pk], 1)],
                             metadata={'msg': random.random()})
    tx1.sign([alice.private_key])
    tx2 = Transaction.create([alice.public_key], [([user_pk], 1)],
                             metadata={'msg': random.random()})
    tx2.sign([alice.private_key])

    with pytest.raises(AssetIdMismatch):
        Transaction.get_asset_id([tx1, tx2])
Пример #4
0
def test_asset_is_separated_from_transaciton(b):
    import copy
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()
    bob = generate_key_pair()

    asset = {'Never gonna': ['give you up',
                             'let you down',
                             'run around'
                             'desert you',
                             'make you cry',
                             'say goodbye',
                             'tell a lie',
                             'hurt you']}

    tx = Transaction.create([alice.public_key],
                            [([bob.public_key], 1)],
                            metadata=None,
                            asset=asset)\
                    .sign([alice.private_key])

    # with store_bulk_transactions we use `insert_many` where PyMongo
    # automatically adds an `_id` field to the tx, therefore we need the
    # deepcopy, for more info see:
    # https://api.mongodb.com/python/current/faq.html#writes-and-ids
    tx_dict = copy.deepcopy(tx.to_dict())

    b.store_bulk_transactions([tx])
    assert 'asset' not in backend.query.get_transaction(b.connection, tx.id)
    assert backend.query.get_asset(b.connection, tx.id)['data'] == asset
    assert b.get_transaction(tx.id).to_dict() == tx_dict
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
    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
Пример #8
0
    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)]
Пример #9
0
    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)]
Пример #10
0
    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
Пример #11
0
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)
Пример #12
0
async def test_subscribe_events(tendermint_ws_url, b):
    from bigchaindb.event_stream import subscribe_events
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.models import Transaction

    session = ClientSession()
    ws = await session.ws_connect(tendermint_ws_url)
    stream_id = 'bigchaindb_stream_01'
    await subscribe_events(ws, stream_id)
    msg = await ws.receive()
    assert msg.data
    msg_data_dict = json.loads(msg.data)
    assert msg_data_dict['id'] == stream_id
    assert msg_data_dict['jsonrpc'] == '2.0'
    assert msg_data_dict['result'] == {}

    alice = generate_key_pair()
    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset=None)\
                    .sign([alice.private_key])

    b.post_transaction(tx, 'broadcast_tx_async')
    msg = await ws.receive()
    msg_data_dict = json.loads(msg.data)
    raw_txn = msg_data_dict['result']['data']['value']['block']['data']['txs'][0]
    transaction = json.loads(base64.b64decode(raw_txn).decode('utf8'))

    assert transaction == tx.to_dict()
Пример #13
0
def test_memoize_from_dict(b):
    alice = generate_key_pair()
    asset = {
        'data': {'id': 'test_id'},
    }

    assert from_dict.cache_info().hits == 0
    assert from_dict.cache_info().misses == 0

    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset=asset,)\
                    .sign([alice.private_key])
    tx_dict = deepcopy(tx.to_dict())

    Transaction.from_dict(tx_dict)

    assert from_dict.cache_info().hits == 0
    assert from_dict.cache_info().misses == 1

    Transaction.from_dict(tx_dict)
    Transaction.from_dict(tx_dict)

    assert from_dict.cache_info().hits == 2
    assert from_dict.cache_info().misses == 1
Пример #14
0
def test_post_create_transaction_with_invalid_id(mock_logger, b, client):
    from bigchaindb.common.exceptions import InvalidHash
    from bigchaindb.models import Transaction
    user_priv, user_pub = crypto.generate_key_pair()

    tx = Transaction.create([user_pub], [([user_pub], 1)])
    tx = tx.sign([user_priv]).to_dict()
    tx['id'] = 'abcd' * 16

    res = client.post(TX_ENDPOINT, data=json.dumps(tx))
    expected_status_code = 400
    expected_error_message = (
        "Invalid transaction ({}): The transaction's id '{}' isn't equal to "
        "the hash of its body, i.e. it's not valid."
    ).format(InvalidHash.__name__, tx['id'])
    assert res.status_code == expected_status_code
    assert res.json['message'] == expected_error_message
    assert mock_logger.error.called
    assert (
        'HTTP API error: %(status)s - %(method)s:%(path)s - %(message)s' in
        mock_logger.error.call_args[0]
    )
    assert (
        {
            'message': expected_error_message, 'status': expected_status_code,
            'method': 'POST', 'path': TX_ENDPOINT
        } in mock_logger.error.call_args[0]
    )
Пример #15
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'
Пример #16
0
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)
Пример #17
0
def test_post_create_transaction_with_language(b, client, nested, language,
                                               expected_status_code):
    from bigchaindb.models import Transaction
    from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection

    if isinstance(b.connection, LocalMongoDBConnection):
        user_priv, user_pub = crypto.generate_key_pair()
        lang_obj = {'language': language}

        if nested:
            asset = {'root': lang_obj}
        else:
            asset = lang_obj

        tx = Transaction.create([user_pub], [([user_pub], 1)],
                                asset=asset)
        tx = tx.sign([user_priv])
        res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict()))
        assert res.status_code == expected_status_code
        if res.status_code == 400:
            expected_error_message = (
                'Invalid transaction (ValidationError): MongoDB does not support '
                'text search for the language "{}". If you do not understand this '
                'error message then please rename key/field "language" to something '
                'else like "lang".').format(language)
            assert res.json['message'] == expected_error_message
Пример #18
0
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)
Пример #19
0
    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)
Пример #20
0
def test_websocket_block_event(b, test_client, loop):
    from bigchaindb import events
    from bigchaindb.web.websocket_server import init_app, POISON_PILL, EVENTS_ENDPOINT
    from bigchaindb.models import Transaction
    from bigchaindb.common import crypto

    user_priv, user_pub = crypto.generate_key_pair()
    tx = Transaction.create([user_pub], [([user_pub], 1)])
    tx = tx.sign([user_priv])

    event_source = asyncio.Queue(loop=loop)
    app = init_app(event_source, loop=loop)
    client = yield from test_client(app)
    ws = yield from client.ws_connect(EVENTS_ENDPOINT)
    block = {'height': 1, 'transactions': [tx.to_dict()]}
    block_event = events.Event(events.EventTypes.BLOCK_VALID, block)

    yield from event_source.put(block_event)

    for tx in block['transactions']:
        result = yield from ws.receive()
        json_result = json.loads(result.data)
        assert json_result['transaction_id'] == tx['id']
        # Since the transactions are all CREATEs, asset id == transaction id
        assert json_result['asset_id'] == tx['id']
        assert json_result['height'] == block['height']

    yield from event_source.put(POISON_PILL)
Пример #21
0
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)
Пример #22
0
def test_deliver_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

    alice = generate_key_pair()
    bob = generate_key_pair()

    tx = Transaction.create([alice.public_key],
                            [([bob.public_key], 1)])\
                    .sign([alice.private_key])

    app = App(b)
    app.init_chain(init_chain_request)

    begin_block = RequestBeginBlock()
    app.begin_block(begin_block)

    result = app.deliver_tx(encode_tx_to_bytes(tx))
    assert result.code == CodeTypeOk

    app.end_block(RequestEndBlock(height=99))
    app.commit()

    assert b.get_transaction(tx.id).id == tx.id
    result = app.deliver_tx(encode_tx_to_bytes(tx))
    assert result.code == CodeTypeError
Пример #23
0
def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_request):
    import multiprocessing as mp
    from bigchaindb import App
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()
    bob = generate_key_pair()
    events = mp.Queue()

    tx = Transaction.create([alice.public_key],
                            [([bob.public_key], 1)])\
                    .sign([alice.private_key])

    app = App(b, events)

    app.init_chain(init_chain_request)

    begin_block = RequestBeginBlock()
    app.begin_block(begin_block)

    result = app.deliver_tx(encode_tx_to_bytes(tx))
    assert result.code == CodeTypeOk

    app.end_block(RequestEndBlock(height=99))
    app.commit()
    assert b.get_transaction(tx.id).id == tx.id
    block_event = events.get()
    assert block_event.data['transactions'] == [tx]
Пример #24
0
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)
Пример #25
0
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
Пример #26
0
def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b):
    from bigchaindb.models import Transaction

    tx = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()})
    tx_signed = tx.sign([alice.private_key])

    assert tx_signed.validate(b) == tx_signed
    assert len(tx_signed.outputs) == 1
    assert tx_signed.outputs[0].amount == 100
    assert len(tx_signed.inputs) == 1
Пример #27
0
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
Пример #28
0
    def test_double_inclusion(self, b, alice):
        from bigchaindb.models import Transaction
        from bigchaindb.backend.exceptions import OperationError

        tx = Transaction.create([alice.public_key], [([alice.public_key], 1)])
        tx = tx.sign([alice.private_key])

        b.store_bulk_transactions([tx])

        with pytest.raises(OperationError):
            b.store_bulk_transactions([tx])
Пример #29
0
def test_post_transaction_invalid_mode(b):
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.common.exceptions import ValidationError
    alice = generate_key_pair()
    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset=None) \
        .sign([alice.private_key]).to_dict()
    tx = b.validate_transaction(tx)
    with pytest.raises(ValidationError):
        b.write_transaction(tx, 'nope')
Пример #30
0
def test_validation_error(b):
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()
    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset=None)\
                    .sign([alice.private_key]).to_dict()

    tx['metadata'] = ''
    assert not b.validate_transaction(tx)
Пример #31
0
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
Пример #32
0
def test_muiltiple_in_mix_own_multiple_out_mix_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], 50),
                                        ([alice.public_key, user_pk], 50)],
                                       asset_id=tx_create.id)
    tx_transfer_signed = tx_transfer.sign([alice.private_key, 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
Пример #33
0
def test_upsert_validator(b, alice):
    from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
    from bigchaindb.backend import query, connect
    from bigchaindb.models import Transaction
    from bigchaindb.tendermint_utils import public_key_to_base64
    import time

    conn = connect()
    power = 1
    public_key = '9B3119650DF82B9A5D8A12E38953EA47475C09F0C48A4E6A0ECE182944B24403'

    validator = {
        'pub_key': {
            'type': 'AC26791624DE60',
            'data': public_key
        },
        'power': power
    }
    validator_update = {
        'validator': validator,
        'update_id': VALIDATOR_UPDATE_ID
    }

    query.store_validator_update(conn, deepcopy(validator_update))

    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
    time.sleep(5)

    validators = b.get_validators()
    validators = [(v['pub_key']['value'], v['voting_power'])
                  for v in validators]

    public_key64 = public_key_to_base64(public_key)
    assert ((public_key64, str(power)) in validators)
Пример #34
0
    def test_get_owned_ids_single_tx_single_output_invalid_block(
            self, b, user_sk, user_pk, genesis_block, 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])
        block = b.create_block([tx])
        b.write_block(block)

        # vote the block VALID
        vote = b.vote(block.id, genesis_block.id, True)
        b.write_vote(vote)

        owned_inputs_user1 = b.get_owned_ids(user_pk)
        owned_inputs_user2 = b.get_owned_ids(user2_pk)
        assert owned_inputs_user1 == [TransactionLink(tx.id, 0)]
        assert owned_inputs_user2 == []

        # NOTE: The transaction itself is valid, still will mark the block
        #       as invalid to mock the behavior.
        tx_invalid = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)],
                                          asset_id=tx.id)
        tx_invalid = tx_invalid.sign([user_sk])
        block = b.create_block([tx_invalid])
        b.write_block(block)

        # vote the block invalid
        vote = b.vote(block.id, b.get_last_voted_block().id, False)
        b.write_vote(vote)

        owned_inputs_user1 = b.get_owned_ids(user_pk)
        owned_inputs_user2 = b.get_owned_ids(user2_pk)

        # should be the same as before (note tx, not tx_invalid)
        assert owned_inputs_user1 == [TransactionLink(tx.id, 0)]
        assert owned_inputs_user2 == []
Пример #35
0
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])

    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])

    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])

    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])

    tx_5 = Transaction.transfer(
        tx_2.to_inputs()[0:1],
        [([alice.public_key], 2)],
        asset_id=tx_1.id,
    ).sign([bob.private_key])
    block_5 = b.create_block([tx_1, tx_2, tx_3, tx_4, tx_5])
    b.write_block(block_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)
Пример #36
0
def test_deliver_transfer_tx__double_spend_fails(b):
    from bigchaindb import App
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair

    app = App(b)
    app.init_chain(['ignore'])

    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
Пример #37
0
    def test_couple_assets(self, b):
        from bigchaindb.models import Block, Transaction

        assets = [
            {
                'msg': '1'
            },
            {
                'msg': '2'
            },
            {
                'msg': '3'
            },
        ]

        txs = []
        # create 3 assets
        for asset in assets:
            tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
            tx.sign([b.me_private])
            txs.append(tx)

        # create a `TRANSFER` transaction.
        # the asset in `TRANSFER` transactions is not extracted
        tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
                                  asset_id=txs[0].id)
        tx.sign([b.me_private])
        txs.append(tx)

        # create the block
        block = Block(txs)
        # decouple assets
        assets_from_block, block_dict = block.decouple_assets()

        # reconstruct the block
        block_dict_reconstructed = Block.couple_assets(block_dict,
                                                       assets_from_block)

        # check that the reconstructed block is the same as the original block
        assert block == Block.from_dict(block_dict_reconstructed)
Пример #38
0
def test_upsert_validator(b, alice):
    from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
    from bigchaindb.backend import query, connect
    from bigchaindb.models import Transaction
    from bigchaindb.tendermint.utils import public_key_to_base64
    import time

    conn = connect()
    public_key = '1718D2DBFF00158A0852A17A01C78F4DCF3BA8E4FB7B8586807FAC182A535034'
    power = 1

    validator = {
        'pub_key': {
            'type': 'AC26791624DE60',
            'data': public_key
        },
        'power': power
    }
    validator_update = {
        'validator': validator,
        'update_id': VALIDATOR_UPDATE_ID
    }

    query.store_validator_update(conn, deepcopy(validator_update))

    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
    time.sleep(5)

    validators = b.get_validators()
    validators = [(v['pub_key']['value'], v['voting_power'])
                  for v in validators]

    public_key64 = public_key_to_base64(public_key)
    assert ((public_key64, power) in validators)
def test_invalid_id_tx_in_block_voting(monkeypatch, b, user_pk, genesis_block):
    from bigchaindb.backend import query
    from bigchaindb.common import crypto, utils
    from bigchaindb.models import Transaction
    from bigchaindb.pipelines import vote

    inpipe = Pipe()
    outpipe = Pipe()

    monkeypatch.setattr('time.time', lambda: 1111111111)
    vote_pipeline = vote.create_pipeline()
    vote_pipeline.setup(indata=inpipe, outdata=outpipe)

    # NOTE: `tx` is invalid, because its id is not corresponding to its content
    tx = Transaction.create([b.me], [([b.me], 1)])
    tx = tx.sign([b.me_private])
    block = b.create_block([tx]).to_dict()
    block['block']['transactions'][0]['id'] = 'an invalid tx id'

    inpipe.put(block)
    vote_pipeline.start()
    vote_out = outpipe.get()
    vote_pipeline.terminate()

    vote_rs = query.get_votes_by_block_id_and_voter(b.connection, block['id'],
                                                    b.me)
    vote_doc = vote_rs.next()
    assert vote_out['vote'] == vote_doc['vote']
    assert vote_doc['vote'] == {
        'voting_for_block': block['id'],
        'previous_block': genesis_block.id,
        'is_block_valid': False,
        'invalid_reason': None,
        'timestamp': '1111111111'
    }

    serialized_vote = utils.serialize(vote_doc['vote']).encode()
    assert vote_doc['node_pubkey'] == b.me
    assert crypto.PublicKey(b.me).verify(serialized_vote,
                                         vote_doc['signature']) is True
Пример #40
0
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
Пример #41
0
def test_post_create_transaction_with_invalid_schema(mock_logger, client):
    from bigchaindb.models import Transaction
    user_priv, user_pub = crypto.generate_key_pair()
    tx = Transaction.create([user_pub], [([user_pub], 1)]).to_dict()
    del tx['version']
    ed25519 = Ed25519Sha256(public_key=base58.b58decode(user_pub))
    message = json.dumps(
        tx,
        sort_keys=True,
        separators=(',', ':'),
        ensure_ascii=False,
    ).encode()
    ed25519.sign(message, base58.b58decode(user_priv))
    tx['inputs'][0]['fulfillment'] = ed25519.serialize_uri()
    tx['id'] = sha3_256(
        json.dumps(
            tx,
            sort_keys=True,
            separators=(',', ':'),
            ensure_ascii=False,
        ).encode(),
    ).hexdigest()
    res = client.post(TX_ENDPOINT, data=json.dumps(tx))
    expected_status_code = 400
    expected_error_message = (
        "Invalid transaction schema: 'version' is a required property")
    assert res.status_code == expected_status_code
    assert res.json['message'] == expected_error_message
    assert mock_logger.error.called
    assert (
        'HTTP API error: %(status)s - %(method)s:%(path)s - %(message)s' in
        mock_logger.error.call_args[0]
    )
    assert (
        {
            'message': expected_error_message, 'status': expected_status_code,
            'method': 'POST', 'path': TX_ENDPOINT
        } in mock_logger.error.call_args[0]
    )
Пример #42
0
    def test_sign_block(self, b):
        from bigchaindb.common.crypto import PrivateKey, PublicKey
        from bigchaindb.common.utils import gen_timestamp, serialize
        from bigchaindb.models import Block, Transaction

        transactions = [Transaction.create([b.me], [([b.me], 1)])]
        timestamp = gen_timestamp()
        voters = ['Qaaa', 'Qbbb']
        expected_block = {
            'timestamp': timestamp,
            'transactions': [tx.to_dict() for tx in transactions],
            'node_pubkey': b.me,
            'voters': voters,
        }
        expected_block_serialized = serialize(expected_block).encode()
        expected = PrivateKey(b.me_private).sign(expected_block_serialized)
        block = Block(transactions, b.me, timestamp, voters)
        block = block.sign(b.me_private)
        assert block.signature == expected.decode()

        public_key = PublicKey(b.me)
        assert public_key.verify(expected_block_serialized, block.signature)
Пример #43
0
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])

    b.store_bulk_transactions([tx])

    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)
Пример #44
0
def inputs_shared(user_pk, user2_pk, genesis_block):
    from bigchaindb.models import Transaction

    # create blocks with transactions for `USER` to spend
    prev_block_id = genesis_block.id
    for block in range(4):
        transactions = [
            Transaction.create(
                [b.me],
                [user_pk, user2_pk],
                metadata={
                    'msg': random.random()
                },
            ).sign([b.me_private]) for _ in range(10)
        ]
        block = b.create_block(transactions)
        b.write_block(block)

        # vote the blocks valid, so that the inputs are valid
        vote = b.vote(block.id, prev_block_id, True)
        prev_block_id = block.id
        b.write_vote(vote)
def test_cant_spend_same_input_twice_in_tx(b, 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

    b.store_bulk_transactions([tx_create_signed])

    # 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)
Пример #46
0
def test_get_metadata_tendermint(client, b, alice):
    from bigchaindb.models import Transaction

    # test returns empty list when no assets are found
    res = client.get(METADATA_ENDPOINT + '?search=abc')
    assert res.json == []
    assert res.status_code == 200

    # create asset
    asset = {'msg': 'abc'}
    metadata = {'key': 'my_meta'}
    tx = Transaction.create([alice.public_key], [([alice.public_key], 1)],
                            metadata=metadata,
                            asset=asset).sign([alice.private_key])

    b.store_bulk_transactions([tx])

    # test that metadata is returned
    res = client.get(METADATA_ENDPOINT + '?search=my_meta')
    assert res.status_code == 200
    assert len(res.json) == 1
    assert res.json[0] == {'metadata': {'key': 'my_meta'}, 'id': tx.id}
Пример #47
0
def test_sum_amount(alice, b, user_pk, user_sk):
    from bigchaindb.models import Transaction

    # CREATE divisible asset with 3 outputs with amount 1
    tx_create = Transaction.create([alice.public_key], [([user_pk], 1),
                                                        ([user_pk], 1),
                                                        ([user_pk], 1)],
                                   asset={'name': random.random()})
    tx_create_signed = tx_create.sign([alice.private_key])

    # create a transfer transaction with one output and check if the amount
    # is 3
    tx_transfer = Transaction.transfer(tx_create.to_inputs(),
                                       [([alice.public_key], 3)],
                                       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 == 3
Пример #48
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
Пример #49
0
def test_deliver_tx__valid_create_updates_db(b):
    from bigchaindb.tendermint import App
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()
    bob = generate_key_pair()

    tx = Transaction.create([alice.public_key],
                            [([bob.public_key], 1)])\
                    .sign([alice.private_key])

    app = App(b)
    app.init_chain(['ignore'])
    app.begin_block('ignore')

    result = app.deliver_tx(encode_tx_to_bytes(tx))
    assert result.is_ok()

    app.end_block(99)
    app.commit()
    assert b.get_transaction(tx.id).id == tx.id
    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)
        ]
Пример #51
0
def test_multiple_in_single_own_single_out_single_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], 50),
                                                        ([user_pk], 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([user_sk])

    b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])

    assert tx_transfer_signed.validate(b)
    assert len(tx_transfer_signed.outputs) == 1
    assert tx_transfer_signed.outputs[0].amount == 100
    assert len(tx_transfer_signed.inputs) == 2
Пример #52
0
    def test_get_asset_ids(self, b):
        from bigchaindb.models import Block, Transaction

        assets = [
            {
                'msg': '1'
            },
            {
                'msg': '2'
            },
            {
                'msg': '3'
            },
        ]

        txs = []
        # create 3 assets
        for asset in assets:
            tx = Transaction.create([b.me], [([b.me], 1)], asset=asset)
            tx.sign([b.me_private])
            txs.append(tx)

        # create a `TRANSFER` transaction.
        # the asset in `TRANSFER` transactions is not extracted
        tx = Transaction.transfer(txs[0].to_inputs(), [([b.me], 1)],
                                  asset_id=txs[0].id)
        tx.sign([b.me_private])
        txs.append(tx)

        # create the block
        block = Block(txs)
        # decouple assets
        assets_from_block, block_dict = block.decouple_assets()

        # get the asset_ids and check that they are the same as the `CREATE`
        # transactions
        asset_ids = Block.get_asset_ids(block_dict)
        assert asset_ids == [tx.id for tx in txs[:-1]]
Пример #53
0
def test_filter_spent_outputs(b, user_pk, user_sk):
    out = [([user_pk], 1)]
    tx1 = Transaction.create([user_pk], out * 3)
    tx1.sign([user_sk])
    # There are 3 inputs
    inputs = tx1.to_inputs()

    # Each spent individually
    tx2 = Transaction.transfer([inputs[0]], out, tx1.id)
    tx2.sign([user_sk])
    tx3 = Transaction.transfer([inputs[1]], out, tx1.id)
    tx3.sign([user_sk])
    tx4 = Transaction.transfer([inputs[2]], out, tx1.id)
    tx4.sign([user_sk])

    # The CREATE and first TRANSFER are valid. tx2 produces a new unspent.
    for tx in [tx1, tx2]:
        block = Block([tx])
        b.write_block(block)
        b.write_vote(b.vote(block.id, '', True))

    # The second TRANSFER is invalid. inputs[1] remains unspent.
    block = Block([tx3])
    b.write_block(block)
    b.write_vote(b.vote(block.id, '', False))

    # The third TRANSFER is undecided. It procuces a new unspent.
    block = Block([tx4])
    b.write_block(block)

    outputs = b.fastquery.get_outputs_by_public_key(user_pk)
    unspents = b.fastquery.filter_spent_outputs(outputs)

    assert set(unspents) == {
        inputs[1].fulfills,
        tx2.to_inputs()[0].fulfills,
        tx4.to_inputs()[0].fulfills
    }
Пример #54
0
    def test_get_spent_single_tx_multiple_outputs(self, b, user_sk, user_pk,
                                                  alice):
        from bigchaindb.common import crypto
        from bigchaindb.models import Transaction

        # create a new users
        user2_sk, user2_pk = crypto.generate_key_pair()

        # create a divisible asset with 3 outputs
        tx_create = Transaction.create([alice.public_key], [([user_pk], 1),
                                                            ([user_pk], 1),
                                                            ([user_pk], 1)])
        tx_create_signed = tx_create.sign([alice.private_key])
        block = b.create_block([tx_create_signed])
        b.write_block(block)

        owned_inputs_user1 = b.get_owned_ids(user_pk)

        # check spents
        for input_tx in owned_inputs_user1:
            assert b.get_spent(input_tx.txid, input_tx.output) is None

        # transfer the first 2 inputs
        tx_transfer = Transaction.transfer(tx_create.to_inputs()[:2],
                                           [([user2_pk], 1), ([user2_pk], 1)],
                                           asset_id=tx_create.id)
        tx_transfer_signed = tx_transfer.sign([user_sk])
        block = b.create_block([tx_transfer_signed])
        b.write_block(block)

        # check that used inputs are marked as spent
        for ffill in tx_create.to_inputs()[:2]:
            spent_tx = b.get_spent(ffill.fulfills.txid, ffill.fulfills.output)
            assert spent_tx == tx_transfer_signed

        # check if remaining transaction that was unspent is also perceived
        # spendable by BigchainDB
        assert b.get_spent(tx_create.to_inputs()[2].fulfills.txid, 2) is None
Пример #55
0
def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request):
    from bigchaindb import App
    from bigchaindb.backend import query
    from bigchaindb.models import Transaction

    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset={'msg': 'live long and prosper'})\
                    .sign([alice.private_key])

    app = App(b)
    app.init_chain(init_chain_request)

    begin_block = RequestBeginBlock()
    app.begin_block(begin_block)
    app.deliver_tx(encode_tx_to_bytes(tx))
    app.end_block(RequestEndBlock(height=99))

    resp = query.get_pre_commit_state(b.connection)
    assert resp['height'] == 99
    assert resp['transactions'] == [tx.id]

    app.begin_block(begin_block)
    app.deliver_tx(encode_tx_to_bytes(tx))
    app.end_block(RequestEndBlock(height=100))
    resp = query.get_pre_commit_state(b.connection)
    assert resp['height'] == 100
    assert resp['transactions'] == [tx.id]

    # simulate a chain migration and assert the height is shifted
    b.store_abci_chain(100, 'new-chain')
    app = App(b)
    app.begin_block(begin_block)
    app.deliver_tx(encode_tx_to_bytes(tx))
    app.end_block(RequestEndBlock(height=1))
    resp = query.get_pre_commit_state(b.connection)
    assert resp['height'] == 101
    assert resp['transactions'] == [tx.id]
Пример #56
0
    def test_block_serialization(self, b, alice):
        from bigchaindb.common.crypto import hash_data
        from bigchaindb.common.utils import gen_timestamp, serialize
        from bigchaindb.models import Block, Transaction

        transactions = [
            Transaction.create([alice.public_key], [([alice.public_key], 1)])
        ]
        timestamp = gen_timestamp()
        expected_block = {
            'timestamp': timestamp,
            'transactions': [tx.to_dict() for tx in transactions],
            'node_pubkey': alice.public_key,
        }
        expected = {
            'id': hash_data(serialize(expected_block)),
            'block': expected_block,
            'signature': None,
        }

        block = Block(transactions, alice.public_key, timestamp)

        assert block.to_dict() == expected
Пример #57
0
    def test_sign_block(self, b, alice):
        from bigchaindb.common.crypto import PrivateKey, PublicKey
        from bigchaindb.common.utils import gen_timestamp, serialize
        from bigchaindb.models import Block, Transaction

        transactions = [
            Transaction.create([alice.public_key], [([alice.public_key], 1)])
        ]
        timestamp = gen_timestamp()
        expected_block = {
            'timestamp': timestamp,
            'transactions': [tx.to_dict() for tx in transactions],
            'node_pubkey': alice.public_key,
        }
        expected_block_serialized = serialize(expected_block).encode()
        expected = PrivateKey(
            alice.private_key).sign(expected_block_serialized)
        block = Block(transactions, alice.public_key, timestamp)
        block = block.sign(alice.private_key)
        assert block.signature == expected.decode()

        public_key = PublicKey(alice.public_key)
        assert public_key.verify(expected_block_serialized, block.signature)
Пример #58
0
def test_get_assets_tendermint(client, tb, alice):
    from bigchaindb.models import Transaction

    # test returns empty list when no assets are found
    res = client.get(ASSETS_ENDPOINT + '?search=abc')
    assert res.json == []
    assert res.status_code == 200

    # create asset
    asset = {'msg': 'abc'}
    tx = Transaction.create([alice.public_key], [([alice.public_key], 1)],
                            asset=asset).sign([alice.private_key])

    tb.store_transaction(tx)

    # test that asset is returned
    res = client.get(ASSETS_ENDPOINT + '?search=abc')
    assert res.status_code == 200
    assert len(res.json) == 1
    assert res.json[0] == {
        'data': {'msg': 'abc'},
        'id': tx.id
    }
Пример #59
0
    def test_get_last_voted_block_cyclic_blockchain(self, b, monkeypatch,
                                                    alice):
        from bigchaindb.common.crypto import PrivateKey
        from bigchaindb.common.exceptions import CyclicBlockchainError
        from bigchaindb.common.utils import serialize
        from bigchaindb.models import Transaction

        tx = Transaction.create([alice.public_key], [([alice.public_key], 1)])
        tx = tx.sign([alice.private_key])
        monkeypatch.setattr('time.time', lambda: 1)
        block1 = b.create_block([tx])
        b.write_block(block1)

        # Manipulate vote to create a cyclic Blockchain
        vote = b.vote(block1.id, b.get_last_voted_block().id, True)
        vote['vote']['previous_block'] = block1.id
        vote_data = serialize(vote['vote'])
        vote['signature'] = PrivateKey(alice.private_key).sign(
            vote_data.encode())
        b.write_vote(vote)

        with pytest.raises(CyclicBlockchainError):
            b.get_last_voted_block()
Пример #60
0
    def test_block_serialization(self, b):
        from bigchaindb.common.crypto import hash_data
        from bigchaindb.common.utils import gen_timestamp, serialize
        from bigchaindb.models import Block, Transaction

        transactions = [Transaction.create([b.me], [([b.me], 1)])]
        timestamp = gen_timestamp()
        voters = ['Qaaa', 'Qbbb']
        expected_block = {
            'timestamp': timestamp,
            'transactions': [tx.to_dict() for tx in transactions],
            'node_pubkey': b.me,
            'voters': voters,
        }
        expected = {
            'id': hash_data(serialize(expected_block)),
            'block': expected_block,
            'signature': None,
        }

        block = Block(transactions, b.me, timestamp, voters)

        assert block.to_dict() == expected