Example #1
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]
Example #2
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'
Example #3
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
Example #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
Example #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
Example #6
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
Example #7
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)
Example #8
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
Example #9
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
Example #10
0
def test_check_tx__unsigned_create_is_error(b):
    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)])

    app = App(b)
    result = app.check_tx(encode_tx_to_bytes(tx))
    assert result.code == CodeTypeError
Example #11
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
Example #12
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)]
Example #13
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)]
Example #14
0
def run_start(args):
    """Start the processes to run the node"""
    logger.info('BigchainDB Version {}'.format(bigchaindb.__version__))

    bigchaindb.config_utils.autoconfigure(filename=args.config, force=True)

    if args.allow_temp_keypair:
        if not (bigchaindb.config['keypair']['private'] or
                bigchaindb.config['keypair']['public']):

            private_key, public_key = crypto.generate_key_pair()
            bigchaindb.config['keypair']['private'] = private_key
            bigchaindb.config['keypair']['public'] = public_key
        else:
            logger.warning('Keypair found, no need to create one on the fly.')

    if args.start_rethinkdb:
        try:
            proc = utils.start_rethinkdb()
        except StartupError as e:
            sys.exit('Error starting RethinkDB, reason is: {}'.format(e))
        logger.info('RethinkDB started with PID %s' % proc.pid)

    try:
        db.init()
    except DatabaseAlreadyExists:
        pass
    except KeypairNotFoundException:
        sys.exit("Can't start BigchainDB, no keypair found. "
                 'Did you run `bigchaindb configure`?')

    logger.info('Starting BigchainDB main process with public key %s',
                bigchaindb.config['keypair']['public'])
    processes.start()
def test_eventify_block_works_with_any_transaction():
    from bigchaindb.web.websocket_server import eventify_block
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.lib import Transaction

    alice = generate_key_pair()

    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)])\
                    .sign([alice.private_key])
    tx_transfer = Transaction.transfer(tx.to_inputs(),
                                       [([alice.public_key], 1)],
                                       asset_id=tx.id)\
                             .sign([alice.private_key])

    block = {'height': 1,
             'transactions': [tx, tx_transfer]}

    expected_events = [{
            'height': 1,
            'asset_id': tx.id,
            'transaction_id': tx.id
        }, {
            'height': 1,
            'asset_id': tx_transfer.asset['id'],
            'transaction_id': tx_transfer.id
        }]

    for event, expected in zip(eventify_block(block), expected_events):
        assert event == expected
Example #16
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]
    )
Example #17
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
Example #18
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)
Example #19
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
Example #20
0
def run_start(args):
    """Start the processes to run the node"""
    logger.info('BigchainDB Version %s', bigchaindb.__version__)

    if args.allow_temp_keypair:
        if not (bigchaindb.config['keypair']['private'] or
                bigchaindb.config['keypair']['public']):

            private_key, public_key = crypto.generate_key_pair()
            bigchaindb.config['keypair']['private'] = private_key
            bigchaindb.config['keypair']['public'] = public_key
        else:
            logger.warning('Keypair found, no need to create one on the fly.')

    if args.start_rethinkdb:
        try:
            proc = utils.start_rethinkdb()
        except StartupError as e:
            sys.exit(RETHINKDB_STARTUP_ERROR.format(e))
        logger.info('RethinkDB started with PID %s' % proc.pid)

    try:
        _run_init()
    except DatabaseAlreadyExists:
        pass
    except KeypairNotFoundException:
        sys.exit(CANNOT_START_KEYPAIR_NOT_FOUND)

    logger.info('Starting BigchainDB main process with public key %s',
                bigchaindb.config['keypair']['public'])
    processes.start()
def test_upsert_validator_delegate_election_vote(b_mock, valid_upsert_validator_election, ed25519_node_keys):
    alice = generate_key_pair()

    b_mock.store_bulk_transactions([valid_upsert_validator_election])

    input0 = valid_upsert_validator_election.to_inputs()[0]
    votes = valid_upsert_validator_election.outputs[0].amount
    public_key0 = input0.owners_before[0]
    key0 = ed25519_node_keys[public_key0]

    delegate_vote = Vote.generate([input0],
                                  [([alice.public_key], 3), ([key0.public_key], votes-3)],
                                  election_id=valid_upsert_validator_election.id)\
        .sign([key0.private_key])

    assert delegate_vote.validate(b_mock)

    b_mock.store_bulk_transactions([delegate_vote])
    election_pub_key = ValidatorElection.to_public_key(valid_upsert_validator_election.id)

    alice_votes = delegate_vote.to_inputs()[0]
    alice_casted_vote = Vote.generate([alice_votes],
                                      [([election_pub_key], 3)],
                                      election_id=valid_upsert_validator_election.id)\
        .sign([alice.private_key])
    assert alice_casted_vote.validate(b_mock)

    key0_votes = delegate_vote.to_inputs()[1]
    key0_casted_vote = Vote.generate([key0_votes],
                                     [([election_pub_key], votes-3)],
                                     election_id=valid_upsert_validator_election.id)\
        .sign([key0.private_key])
    assert key0_casted_vote.validate(b_mock)
Example #22
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()
def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_key):
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()
    voters = ValidatorElection.recipients(b_mock)
    election = ValidatorElection.generate([node_key.public_key, alice.public_key],
                                          voters,
                                          new_validator, None).sign([node_key.private_key, alice.private_key])
    with pytest.raises(MultipleInputsError):
        election.validate(b_mock)
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
Example #25
0
def run_configure(args, skip_if_exists=False):
    """Run a script to configure the current node.

    Args:
        skip_if_exists (bool): skip the function if a config file already exists
    """
    config_path = args.config or bigchaindb.config_utils.CONFIG_DEFAULT_PATH

    config_file_exists = False
    # if the config path is `-` then it's stdout
    if config_path != "-":
        config_file_exists = os.path.exists(config_path)

    if config_file_exists and skip_if_exists:
        return

    if config_file_exists and not args.yes:
        want = input(
            "Config file `{}` exists, do you want to override it? " "(cannot be undone) [y/N]: ".format(config_path)
        )
        if want != "y":
            return

    conf = copy.deepcopy(bigchaindb.config)

    # Patch the default configuration with the new values
    conf = bigchaindb.config_utils.update(conf, bigchaindb.config_utils.env_config(bigchaindb.config))

    print("Generating keypair", file=sys.stderr)
    conf["keypair"]["private"], conf["keypair"]["public"] = crypto.generate_key_pair()

    if not args.yes:
        for key in ("bind",):
            val = conf["server"][key]
            conf["server"][key] = input("API Server {}? (default `{}`): ".format(key, val)) or val

        for key in ("host", "port", "name"):
            val = conf["database"][key]
            conf["database"][key] = input("Database {}? (default `{}`): ".format(key, val)) or val

        for key in ("host", "port", "rate"):
            val = conf["statsd"][key]
            conf["statsd"][key] = input("Statsd {}? (default `{}`): ".format(key, val)) or val

        val = conf["backlog_reassign_delay"]
        conf["backlog_reassign_delay"] = (
            input("Stale transaction reassignment delay (in seconds)? (default `{}`): ".format(val)) or val
        )

    if config_path != "-":
        bigchaindb.config_utils.write_config(conf, config_path)
    else:
        print(json.dumps(conf, indent=4, sort_keys=True))
    print("Configuration written to {}".format(config_path), file=sys.stderr)
    print("Ready to go!", file=sys.stderr)
Example #26
0
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
Example #27
0
    def test_single_owner_before_multiple_owners_after_single_input(self, b,
                                                                    user_sk,
                                                                    user_pk,
                                                                    inputs):
        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()
        tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop()

        input_tx = b.get_transaction(tx_link.txid)
        tx = Transaction.transfer(input_tx.to_inputs(),
                                  [([user2_pk, user3_pk], 1)],
                                  asset_id=input_tx.id)
        tx = tx.sign([user_sk])

        tx.validate(b)
        assert len(tx.inputs) == 1
        assert len(tx.outputs) == 1
Example #28
0
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
Example #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')
Example #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)
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)
Example #32
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 == []
Example #33
0
def test_valid_election_votes_received(b_mock, valid_election,
                                       ed25519_node_keys):
    alice = generate_key_pair()
    b_mock.store_bulk_transactions([valid_election])
    assert valid_election.get_commited_votes(b_mock) == 0

    input0 = valid_election.to_inputs()[0]
    votes = valid_election.outputs[0].amount
    public_key0 = input0.owners_before[0]
    key0 = ed25519_node_keys[public_key0]

    # delegate some votes to alice
    delegate_vote = ValidatorElectionVote.generate([input0],
                                                   [([alice.public_key], 4), ([key0.public_key], votes-4)],
                                                   election_id=valid_election.id)\
                                         .sign([key0.private_key])
    b_mock.store_bulk_transactions([delegate_vote])
    assert valid_election.get_commited_votes(b_mock) == 0

    election_public_key = ValidatorElection.to_public_key(valid_election.id)
    alice_votes = delegate_vote.to_inputs()[0]
    key0_votes = delegate_vote.to_inputs()[1]

    alice_casted_vote = ValidatorElectionVote.generate([alice_votes],
                                                       [([election_public_key], 2), ([alice.public_key], 2)],
                                                       election_id=valid_election.id)\
                                             .sign([alice.private_key])

    assert alice_casted_vote.validate(b_mock)
    b_mock.store_bulk_transactions([alice_casted_vote])

    # Check if the delegated vote is count as valid vote
    assert valid_election.get_commited_votes(b_mock) == 2

    key0_casted_vote = ValidatorElectionVote.generate([key0_votes],
                                                      [([election_public_key], votes-4)],
                                                      election_id=valid_election.id)\
                                            .sign([key0.private_key])

    assert key0_casted_vote.validate(b_mock)
    b_mock.store_bulk_transactions([key0_casted_vote])

    assert valid_election.get_commited_votes(b_mock) == votes - 2
Example #34
0
def test_write_and_post_transaction(mock_post, b):
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.tendermint.utils import encode_transaction

    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)
    b.write_transaction(tx, 'broadcast_tx_async')

    assert mock_post.called
    args, kwargs = mock_post.call_args
    assert 'broadcast_tx_async' == kwargs['json']['method']
    encoded_tx = [encode_transaction(tx.to_dict())]
    assert encoded_tx == kwargs['json']['params']
def test_post_invalid_transfer_transaction_returns_400(b, client, user_pk):
    from bigchaindb.models import Transaction
    from bigchaindb.common.exceptions import InvalidSignature

    user_pub = crypto.generate_key_pair()[1]

    input_valid = b.get_owned_ids(user_pk).pop()
    create_tx = b.get_transaction(input_valid.txid)
    transfer_tx = Transaction.transfer(create_tx.to_inputs(),
                                       [([user_pub], 1)],
                                       asset_id=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
Example #36
0
def test_consensus_rules_frontend(b):
    from .utils import create_simple_tx, post_tx

    alice_priv, alice_pub = crypto.generate_key_pair()

    create_a = create_simple_tx(
        alice_pub, alice_priv,
        asset={
            'policy': [
                {
                    'condition': "'INIT' == 'INIT'",
                    'rule': "'INIT' == 'INIT'"
                },
            ]
        },
        metadata={
            'state': "INIT"
        })
    response = post_tx(b, None, create_a)
    assert response.status_code == 202
Example #37
0
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])
Example #38
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])
        block = b.create_block([tx_create_signed])
        b.write_block(block)

        # get input
        owned_inputs_user1 = b.get_owned_ids(user_pk)
        owned_inputs_user2 = b.get_owned_ids(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])
        block = b.create_block([tx_transfer_signed])
        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 == []
        assert owned_inputs_user2 == [
            TransactionLink(tx_transfer.id, 0),
            TransactionLink(tx_transfer.id, 1)
        ]
Example #39
0
def generate_validators(powers):
    """Generates an arbitrary number of validators with random public keys.

       The object under the `storage` key is in the format expected by DB.

       The object under the `eleciton` key is in the format expected by
       the upsert validator election.

       `public_key`, `private_key` are in the format used for signing transactions.

       Args:
           powers: A list of intergers representing the voting power to
                   assign to the corresponding validators.
    """
    validators = []
    for power in powers:
        kp = crypto.generate_key_pair()
        validators.append({
            'storage': {
                'public_key': {
                    'value':
                    key_to_base64(base58.b58decode(kp.public_key).hex()),
                    'type': 'ed25519-base64',
                },
                'voting_power': power,
            },
            'election': {
                'node_id': f'node-{random.choice(range(100))}',
                'power': power,
                'public_key': {
                    'value':
                    base64.b16encode(base58.b58decode(
                        kp.public_key)).decode('utf-8'),
                    'type':
                    'ed25519-base16',
                },
            },
            'public_key': kp.public_key,
            'private_key': kp.private_key,
        })
    return validators
Example #40
0
    def test_get_spent_single_tx_single_output_invalid_block(
            self, b, user_sk, user_pk, genesis_block, alice):
        from bigchaindb.common import crypto
        from bigchaindb.models import Transaction

        # create a new users
        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).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)

        # vote the block invalid
        vote = b.vote(block.id, b.get_last_voted_block().id, False)
        b.write_vote(vote)
        # NOTE: I have no idea why this line is here
        b.get_transaction(tx.id)
        spent_inputs_user1 = b.get_spent(input_txid, input_idx)

        # Now there should be no spents (the block is invalid)
        assert spent_inputs_user1 is None
Example #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)]).sign([user_priv]).to_dict()
    del tx['version']
    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])
Example #42
0
def test_permissions(b):
    from .utils import create_simple_tx, post_tx

    admin_priv, admin_pub = crypto.generate_key_pair()

    # class App():
    #   allowed_permissions = [
    #     'ADD_USER'
    #   ]
    #
    #   def __init__(owner, uuid):
    #     self.uuid = uuid
    #     self.owner = owner
    #     for allowed_permission in allowed_permissions:
    #       self.permissions[allowed_permission] = []
    #
    # admin CREATES permissions ASSET
    # admin CREATES app ASSET
    # admin LINKS permission ID
    #
    #   def grant_permission(permission, user):
    #     self.permissions[permission].append(user)
    #
    #   def revoke_permission(permission, user):
    #     self.permissions[permission].remove(user)
    #

    create_permission_add_user = create_simple_tx(
        admin_pub, admin_priv, asset={'permission': 'ADD_USER'})
    response = post_tx(b, None, create_permission_add_user)
    assert response.status_code == 202

    create_app = create_simple_tx(admin_pub,
                                  admin_priv,
                                  asset={
                                      'uuid': 'app',
                                      'links': create_permission_add_user.id
                                  })
    response = post_tx(b, None, create_app)
    assert response.status_code == 202
def federation(n):
    """
    Return a list of Bigchain objects and pipeline steppers to represent
    a BigchainDB federation
    """
    keys = [generate_key_pair() for _ in range(n)]
    config_orig = bigchaindb.config

    @contextmanager
    def make_nodes(i):
        """
        make_nodes is a recursive context manager. Essentially it is doing:

        with f(a[0]) as b0:
            with f(a[1]) as b1:
                with f(a[2]) as b2:
                    yield [b0, b1, b2]

        with an arbitrary depth. It is also temporarily patching global
        configuration to simulate nodes with separate identities.
        """
        nonlocal keys
        if i == 0:
            yield []
        else:
            config = deepcopy(config_orig)
            keys = [keys[-1]] + keys[:-1]  # Rotate keys
            config['keyring'] = [pub for _, pub in keys[1:]]
            config['keypair']['private'] = keys[0][0]
            config['keypair']['public'] = keys[0][1]
            bigchaindb.config = config
            stepper = create_stepper()
            with stepper.start():
                node = (Bigchain(), stepper)
                with make_nodes(i - 1) as rest:
                    yield [node] + rest

    with make_nodes(n) as steppers:
        bigchaindb.config = config_orig
        yield zip(*steppers)
Example #44
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]
    )
Example #45
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
Example #46
0
def test_roles(b):
    from .utils import create_simple_tx, post_tx

    admin_priv, admin_pub = crypto.generate_key_pair()

    # class AddUserRole():
    #   permissions = [
    #     'ADD_USER'
    #   ]
    #
    #   def __init__(user):
    #     self.user = user
    #
    # class App():
    #   def __init__(owner, uuid):
    #     self.uuid = uuid
    #     self.owner = owner
    #     self.roles = {}
    #
    #   def add_role(role):
    #     self.roles[role.user] = role
    #
    #   def remove_role(role):
    #     self.roles[role.user] = None
    #

    create_permission_add_user = create_simple_tx(
        admin_pub, admin_priv, asset={'permission': 'ADD_USER'})
    response = post_tx(b, None, create_permission_add_user)
    assert response.status_code == 202

    create_app = create_simple_tx(admin_pub,
                                  admin_priv,
                                  asset={
                                      'uuid': 'app',
                                      'links': create_permission_add_user.id
                                  })
    response = post_tx(b, None, create_app)
    assert response.status_code == 202
Example #47
0
def run_start(args):
    """Start the processes to run the node"""
    logger.info('{} Version {}'.format(app_setup_name, bigchaindb.__version__))

    bigchaindb.config_utils.autoconfigure(filename=args.config, force=True)

    if args.allow_temp_keypair:
        if not (bigchaindb.config['keypair']['private']
                or bigchaindb.config['keypair']['public']):

            private_key, public_key = crypto.generate_key_pair()
            bigchaindb.config['keypair']['private'] = private_key
            bigchaindb.config['keypair']['public'] = public_key
        else:
            logger.warning('Keypair found, no need to create one on the fly.')

    if args.start_rethinkdb:
        try:
            proc = utils.start_rethinkdb()
        except StartupError as e:
            sys.exit('Error starting RethinkDB, reason is: {}'.format(e))
        logger.info('RethinkDB started with PID %s' % proc.pid)

    try:
        db.init()
    except DatabaseAlreadyExists:
        pass
    except KeypairNotFoundException:
        sys.exit("Can't start {}, no keypair found. "
                 'Did you run `{} configure`?'.format(app_setup_name,
                                                      app_service_name))

    db.init_databaseData()

    logger.info(
        'Starting {} main process with public key %s'.format(app_setup_name),
        bigchaindb.config['keypair']['public'])
    processes.start()
Example #48
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
Example #49
0
def test_post_create_transaction_with_invalid_key(b, client, field, value,
                                                  err_key,
                                                  expected_status_code):
    from bigchaindb.models import Transaction
    from bigchaindb.backend.mongodb.connection import MongoDBConnection
    user_priv, user_pub = crypto.generate_key_pair()

    if isinstance(b.connection, MongoDBConnection):
        if field == 'asset':
            tx = Transaction.create([user_pub], [([user_pub], 1)], asset=value)
        elif field == 'metadata':
            tx = Transaction.create([user_pub], [([user_pub], 1)],
                                    metadata=value)
        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): Invalid key name "{}" '
                'in {} object. The key name cannot contain characters '
                '".", "$" or null characters').format(err_key, field)
            assert res.json['message'] == expected_error_message
Example #50
0
def test_post_create_transaction_with_invalid_signature(mock_logger,
                                                        b,
                                                        client):
    from bigchaindb.common.exceptions import InvalidSignature
    from bigchaindb.models import Transaction
    user_priv, user_pub = crypto.generate_key_pair()

    tx = Transaction.create([user_pub], [([user_pub], 1)]).to_dict()
    tx['inputs'][0]['fulfillment'] = 64 * '0'
    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 ({}): Fulfillment URI '
        'couldn\'t been parsed'
    ).format(InvalidSignature.__name__)
    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]
    )
def test_recover_db_from_zombie_block(b, monkeypatch):
    from bigchaindb.commands.bigchaindb import run_recover
    from bigchaindb.models import Transaction
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.tendermint.lib import Block
    from bigchaindb import backend

    alice = generate_key_pair()
    tx = Transaction.create([alice.public_key],
                            [([alice.public_key], 1)],
                            asset={'cycle': 'hero'},
                            metadata={'name': 'hohenheim'}) \
        .sign([alice.private_key])
    b.store_bulk_transactions([tx])

    block9 = Block(app_hash='random_app_hash', height=9,
                   transactions=[])._asdict()
    b.store_block(block9)
    block10 = Block(app_hash='random_app_hash',
                    height=10,
                    transactions=[tx.id])._asdict()
    b.store_block(block10)

    def mock_get(uri):
        return MockResponse(9)

    monkeypatch.setattr('requests.get', mock_get)

    run_recover(b)

    assert list(backend.query.get_metadata(b.connection, [tx.id])) == []
    assert not backend.query.get_asset(b.connection, tx.id)
    assert not b.get_transaction(tx.id)

    block = b.get_latest_block()
    assert block['height'] == 9
def test_upsert_validator_delegate_election_vote(b_mock, valid_election,
                                                 ed25519_node_keys):
    from bigchaindb.common.crypto import generate_key_pair

    alice = generate_key_pair()

    b_mock.store_bulk_transactions([valid_election])

    input0 = valid_election.to_inputs()[0]
    votes = valid_election.outputs[0].amount
    public_key0 = input0.owners_before[0]
    key0 = ed25519_node_keys[public_key0]

    delegate_vote = ValidatorElectionVote.generate([input0],
                                                   [([alice.public_key], 3), ([key0.public_key], votes-3)],
                                                   election_id=valid_election.id)\
                                         .sign([key0.private_key])

    assert delegate_vote.validate(b_mock)

    b_mock.store_bulk_transactions([delegate_vote])
    election_pub_key = ValidatorElectionVote.to_public_key(valid_election.id)

    alice_votes = delegate_vote.to_inputs()[0]
    alice_casted_vote = ValidatorElectionVote.generate([alice_votes],
                                                       [([election_pub_key], 3)],
                                                       election_id=valid_election.id)\
                                             .sign([alice.private_key])
    assert alice_casted_vote.validate(b_mock)

    key0_votes = delegate_vote.to_inputs()[1]
    key0_casted_vote = ValidatorElectionVote.generate([key0_votes],
                                                      [([election_pub_key], votes-3)],
                                                      election_id=valid_election.id)\
                                            .sign([key0.private_key])
    assert key0_casted_vote.validate(b_mock)
Example #53
0
def test_get_votes_endpoint_multiple_votes(b, client):
    from bigchaindb.common.crypto import generate_key_pair

    tx = Transaction.create([b.me], [([b.me], 1)])
    tx = tx.sign([b.me_private])

    block = b.create_block([tx])
    b.write_block(block)
    last_block = b.get_last_voted_block().id
    # vote the block valid
    vote_valid = b.vote(block.id, last_block, True)
    b.write_vote(vote_valid)

    # vote the block invalid
    # a note can only vote once so we need a new node_pubkey for the second
    # vote
    _, pk = generate_key_pair()
    vote_invalid = b.vote(block.id, last_block, False)
    vote_invalid['node_pubkey'] = pk
    b.write_vote(vote_invalid)

    res = client.get(VOTES_ENDPOINT + '?block_id=' + block.id)
    assert len(res.json) == 2
    assert res.status_code == 200
Example #54
0
def test_consensus_rules(b):
    from .utils import create_simple_tx, post_tx

    alice_priv, alice_pub = crypto.generate_key_pair()

    create_a = create_simple_tx(
        alice_pub, alice_priv,
        asset={
            'policy': [
                {
                    'condition': 'transaction.metadata["state"] == "INIT"',
                    'rule': 'AMOUNT(transaction.outputs) == 1'
                },
                {
                    'condition': 'transaction.inputs[0].owners_before == "{}"'.format(alice_pub),
                    'rule': 'LEN(transaction.outputs) == 1'
                },
            ]
        },
        metadata={
            'state': "INIT"
        })
    response = post_tx(b, None, create_a)
    assert response.status_code == 202
def test_app(tb):
    from bigchaindb.tendermint import App
    from bigchaindb.tendermint.utils import calculate_hash
    from bigchaindb.common.crypto import generate_key_pair
    from bigchaindb.models import Transaction

    b = tb
    app = App(b)
    p = ProtocolHandler(app)

    data = p.process('info', None)
    res, err = read_message(BytesIO(data), types.Response)
    assert res
    assert res.info.last_block_app_hash == b''
    assert res.info.last_block_height == 0
    assert not b.get_latest_block()

    p.process('init_chain', None)
    block0 = b.get_latest_block()
    assert block0
    assert block0['height'] == 0
    assert block0['app_hash'] == ''

    alice = generate_key_pair()
    bob = generate_key_pair()
    tx = Transaction.create([alice.public_key],
                            [([bob.public_key], 1)])\
                    .sign([alice.private_key])
    etxn = json.dumps(tx.to_dict()).encode('utf8')

    r = to_request_check_tx(etxn)
    data = p.process('check_tx', r)
    res, err = read_message(BytesIO(data), types.Response)
    assert res
    assert res.check_tx.code == 0

    r = types.Request()
    r.begin_block.hash = b''
    p.process('begin_block', r)

    r = to_request_deliver_tx(etxn)
    data = p.process('deliver_tx', r)
    res, err = read_message(BytesIO(data), types.Response)
    assert res
    assert res.deliver_tx.code == 0

    new_block_txn_hash = calculate_hash([tx.id])

    r = types.Request()
    r.end_block.height = 1
    data = p.process('end_block', r)
    res, err = read_message(BytesIO(data), types.Response)
    assert res
    assert 'end_block' == res.WhichOneof('value')

    new_block_hash = calculate_hash([block0['app_hash'], new_block_txn_hash])

    data = p.process('commit', None)
    res, err = read_message(BytesIO(data), types.Response)
    assert res
    assert res.commit.code == 0
    assert res.commit.data == new_block_hash.encode('utf-8')
    assert b.get_transaction(tx.id).id == tx.id

    block0 = b.get_latest_block()
    assert block0
    assert block0['height'] == 1
    assert block0['app_hash'] == new_block_hash

    # empty block should not update height
    r = types.Request()
    r.begin_block.hash = new_block_hash.encode('utf-8')
    p.process('begin_block', r)

    r = types.Request()
    r.end_block.height = 2
    p.process('end_block', r)

    data = p.process('commit', None)
    assert res.commit.data == new_block_hash.encode('utf-8')

    block0 = b.get_latest_block()
    assert block0
    assert block0['height'] == 1

    # when empty block is generated hash of previous block should be returned
    assert block0['app_hash'] == new_block_hash
Example #56
0
def merlin():
    from bigchaindb.common.crypto import generate_key_pair
    return generate_key_pair()
Example #57
0
import os
import copy
import random
from collections import namedtuple
from logging import getLogger
from logging.config import dictConfig

import pytest
from pymongo import MongoClient

from bigchaindb.common import crypto
from bigchaindb.tendermint.lib import Block

TEST_DB_NAME = 'bigchain_test'

USER2_SK, USER2_PK = crypto.generate_key_pair()

# Test user. inputs will be created for this user. Cryptography Keys
USER_PRIVATE_KEY = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie'
USER_PUBLIC_KEY = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE'


def pytest_runtest_setup(item):
    if isinstance(item, item.Function):
        backend = item.session.config.getoption('--database-backend')
        if (item.get_marker('localmongodb') and backend != 'localmongodb'):
            pytest.skip(
                'Skip tendermint specific tests if not using localmongodb')


def pytest_addoption(parser):
Example #58
0
import requests
import time

from bigchaindb.common.transaction import Transaction, Asset, Fulfillment
from bigchaindb.common.crypto import generate_key_pair

# 一对多转账,生成1+3个公钥
pri_1, pub_1 = generate_key_pair()
pri_n1, pub_n1 = generate_key_pair()
pri_n2, pub_n2 = generate_key_pair()
pri_n3, pub_n3 = generate_key_pair()

delay = 4  # 发送交易后,等待建块投票延迟
msg = "1_to_n"
asset = Asset(data={'money': 'RMB'}, data_id='20170628150000', divisible=True)
metadata = {'raw': msg}

# pub_1先创建10000,再转给n1,n2,n3各2000/3000/5000
amount = 10000
amount_n1 = 2000
amount_n2 = 3000
amount_n3 = 5000

# pub_1创建交易
tx = Transaction.create([pub_1], [([pub_1], amount)], metadata=metadata, asset=asset)
tx = tx.sign([pri_1]).to_dict()
print("========create tx======")

# 发送给区块链节点
with requests.Session() as session:
    res = session.post('http://localhost:9984/uniledger/v1/transaction/createOrTransferTx', json=tx)
Example #59
0
import json
import sha3

from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
from cryptoconditions.crypto import Ed25519SigningKey

from bigchaindb.models import Transaction
from bigchaindb.common.crypto import generate_key_pair
from bigchaindb.common.transaction import Output

VW_SK, VW_PK = generate_key_pair()
TEL_SK, TEL_PK = generate_key_pair()


def create_asset(vw_sk, vw_pk, vehicle_id, data, metadata):
    # Create asset VW -> [VW, TEL]
    # Custom crypto condition multisig 1-2
    threshold_fulfillment = ThresholdSha256Fulfillment(threshold=1)

    vw_fulfillment = Ed25519Fulfillment(public_key=vw_pk)
    tel_fulfillment = Ed25519Fulfillment(public_key=vehicle_id)

    threshold_fulfillment.add_subfulfillment(vw_fulfillment)
    threshold_fulfillment.add_subfulfillment(tel_fulfillment)

    output = {
        'amount': 1,
        'condition': {
            'details': threshold_fulfillment.to_dict(),
            'uri': threshold_fulfillment.condition.serialize_uri()
        },
Example #60
0
 def get_key_pair(self):
     return generate_key_pair()