Merge remote-tracking branch 'ssh_upstream/master' into iss/uv-approve

This commit is contained in:
Vanshdeep Singh 2018-08-27 16:04:26 +02:00
commit 785ce7b667
20 changed files with 106 additions and 185 deletions

View File

@ -48,6 +48,17 @@ def _multiprocessing_to_asyncio(in_queue, out_queue, loop):
loop.call_soon_threadsafe(out_queue.put_nowait, value)
def eventify_block(block):
for tx in block['transactions']:
try:
asset_id = tx['asset']['id']
except KeyError:
asset_id = tx['id']
yield {'height': block['height'],
'asset_id': asset_id,
'transaction_id': tx['id']}
class Dispatcher:
"""Dispatch events to websockets.
@ -99,18 +110,10 @@ class Dispatcher:
str_buffer.append(event)
elif event.type == EventTypes.BLOCK_VALID:
block = event.data
str_buffer = map(json.dumps, eventify_block(event.data))
for tx in block['transactions']:
asset_id = tx['asset'].get('id', None)
asset_id = tx['id'] if asset_id is None else asset_id
data = {'height': block['height'],
'asset_id': asset_id,
'transaction_id': tx['id']}
str_buffer.append(json.dumps(data))
for _, websocket in self.subscribers.items():
for str_item in str_buffer:
for _, websocket in self.subscribers.items():
yield from websocket.send_str(str_item)

View File

@ -135,13 +135,21 @@ Transactions
:query string mode: (Optional) One of the three supported modes to send a transaction: ``async``, ``sync``, ``commit``. The default is ``async``.
The ``mode`` query parameter inhereted from the mode parameter in Tendermint's
`broadcast API
<http://tendermint.readthedocs.io/projects/tools/en/master/using-tendermint.html#broadcast-api>`_.
``mode=async`` means the HTTP response will come back immediately, without
even checking to see if the transaction is valid.
``mode=sync`` means the HTTP response will come back once the node has
checked the validity of the transaction.
Once the posted transaction arrives at a BigchainDB node,
that node will check to see if the transaction is valid.
If it's invalid, the node will return an HTTP 400 (error).
Otherwise, the node will send the transaction to Tendermint (in the same node) using the
`Tendermint broadcast API
<https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_.
The meaning of the ``mode`` query parameter is inherited from the mode parameter in
`Tendermint's broadcast API
<https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_.
``mode=async`` means the HTTP response will come back immediately,
before Tendermint asks BigchainDB Server to check the validity of the transaction (a second time).
``mode=sync`` means the HTTP response will come back
after Tendermint gets a response from BigchainDB Server
regarding the validity of the transaction.
``mode=commit`` means the HTTP response will come back once the transaction
is in a committed block.

View File

@ -106,7 +106,7 @@ Here, `E_PUBKEY`, `E_POWER`, and `E_NODE_ID` are the public key, proposed power,
Example usage,
```bash
$ bigchaindb upsert-validator new B0E42D2589A455EAD339A035D6CE1C8C3E25863F268120AA0162AD7D003A4014 1 12345 --private-key /home/user/.tendermint/config/priv_validator.json
$ bigchaindb upsert-validator new HHG0IQRybpT6nJMIWWFWhMczCLHt6xcm7eP52GnGuPY= 1 fb7140f03a4ffad899fabbbf655b97e0321add66 --private-key /home/user/.tendermint/config/priv_validator.json
```
If the command succeeds, it will create an election and return an `election_id`. Elections consist of one vote token per voting power, issued to the members of the validator set. Validators can cast their votes to approve the change to the validator set by spending their vote tokens. The status of the election can be monitored by providing the `election_id` to the `show` subcommand.

View File

@ -55,10 +55,8 @@ def test_get_connection_returns_the_correct_instance(db_host, db_port):
assert conn.conn._topology_settings.replica_set_name == config['replicaset']
@mock.patch('bigchaindb.backend.localmongodb.connection.initialize_replica_set')
@mock.patch('pymongo.MongoClient.__init__')
@mock.patch('time.sleep')
def test_connection_error(mock_sleep, mock_client, mock_init_repl_set):
def test_connection_error(mock_client):
from bigchaindb.backend import connect
from bigchaindb.backend.exceptions import ConnectionError
@ -74,9 +72,7 @@ def test_connection_error(mock_sleep, mock_client, mock_init_repl_set):
assert mock_client.call_count == 3
@mock.patch('bigchaindb.backend.localmongodb.connection.initialize_replica_set')
@mock.patch('pymongo.MongoClient')
def test_connection_run_errors(mock_client, mock_init_repl_set):
def test_connection_run_errors():
from bigchaindb.backend import connect
from bigchaindb.backend.exceptions import (DuplicateKeyError,
OperationError,

View File

@ -7,7 +7,7 @@ from copy import deepcopy
import pytest
import pymongo
pytestmark = [pytest.mark.tendermint, pytest.mark.localmongodb, pytest.mark.bdb]
pytestmark = [pytest.mark.tendermint, pytest.mark.bdb]
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):

View File

@ -27,8 +27,8 @@ def mock_db_init_with_existing_db(monkeypatch):
@pytest.fixture
def mock_processes_start(monkeypatch):
from bigchaindb import processes
monkeypatch.setattr(processes, 'start', lambda *args: None)
from bigchaindb.utils import Process
monkeypatch.setattr(Process, 'run', lambda *args: None)
@pytest.fixture

View File

@ -185,7 +185,7 @@ def test_run_configure_when_config_does_exist(monkeypatch,
mock_bigchaindb_backup_config):
value = {}
def mock_write_config(newconfig, filename=None):
def mock_write_config(newconfig):
value['return'] = newconfig
from bigchaindb.commands.bigchaindb import run_configure
@ -250,11 +250,8 @@ def test_run_start_when_db_already_exists(mocker,
@pytest.mark.tendermint
@patch('argparse.ArgumentParser.parse_args')
@patch('bigchaindb.commands.utils.base_parser')
@patch('bigchaindb.commands.utils.start')
def test_calling_main(start_mock, base_parser_mock, parse_args_mock,
monkeypatch):
def test_calling_main(start_mock, monkeypatch):
from bigchaindb.commands.bigchaindb import main
argparser_mock = Mock()
@ -283,11 +280,9 @@ def test_calling_main(start_mock, base_parser_mock, parse_args_mock,
assert start_mock.called is True
@patch('bigchaindb.config_utils.autoconfigure')
@patch('bigchaindb.commands.bigchaindb.run_recover')
@patch('bigchaindb.start.start')
def test_recover_db_on_start(mock_autoconfigure,
mock_run_recover,
def test_recover_db_on_start(mock_run_recover,
mock_start,
mocked_setup_logging):
from bigchaindb.commands.bigchaindb import run_start

View File

@ -37,13 +37,6 @@ 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):
from bigchaindb.backend.connection import BACKENDS
@ -56,19 +49,6 @@ def pytest_addoption(parser):
)
def pytest_ignore_collect(path, config):
from bigchaindb.backend.connection import BACKENDS
path = str(path)
supported_backends = BACKENDS.keys()
if os.path.isdir(path):
dirname = os.path.split(path)[1]
if dirname in supported_backends and dirname != config.getoption('--database-backend'):
print('Ignoring unrequested backend test dir: ', path)
return True
def pytest_configure(config):
config.addinivalue_line(
'markers',
@ -266,28 +246,12 @@ def merlin():
return generate_key_pair()
@pytest.fixture
def merlin_privkey(merlin):
return merlin.private_key
@pytest.fixture
def merlin_pubkey(merlin):
return merlin.public_key
@pytest.fixture
def b():
from bigchaindb import BigchainDB
return BigchainDB()
@pytest.fixture
def tb():
from bigchaindb import BigchainDB
return BigchainDB()
@pytest.fixture
def create_tx(alice, user_pk):
from bigchaindb.models import Transaction
@ -349,24 +313,6 @@ def inputs(user_pk, b, alice):
b.store_bulk_transactions(transactions)
@pytest.fixture
def inputs_shared(user_pk, user2_pk, alice):
from bigchaindb.models import Transaction
# create blocks with transactions for `USER` to spend
for block in range(4):
transactions = [
Transaction.create(
[alice.public_key],
[user_pk, user2_pk],
metadata={'msg': random.random()},
).sign([alice.private_key]).to_dict()
for _ in range(10)
]
block = Block(app_hash='', height=_get_height(b), transaction=transactions)
b.store_block(block._asdict())
@pytest.fixture
def dummy_db(request):
from bigchaindb.backend import connect, schema
@ -389,26 +335,6 @@ def dummy_db(request):
pass
@pytest.fixture
def not_yet_created_db(request):
from bigchaindb.backend import connect, schema
from bigchaindb.common.exceptions import DatabaseDoesNotExist
conn = connect()
dbname = request.fixturename
xdist_suffix = getattr(request.config, 'slaveinput', {}).get('slaveid')
if xdist_suffix:
dbname = '{}_{}'.format(dbname, xdist_suffix)
try:
schema.drop_database(conn, dbname)
except DatabaseDoesNotExist:
pass
yield dbname
try:
schema.drop_database(conn, dbname)
except DatabaseDoesNotExist:
pass
@pytest.fixture
def db_config():
from bigchaindb import config
@ -464,29 +390,6 @@ def tendermint_ws_url(tendermint_host, tendermint_port):
return 'ws://{}:{}/websocket'.format(tendermint_host, tendermint_port)
@pytest.fixture
def tendermint_context(tendermint_host, tendermint_port, tendermint_ws_url):
TendermintContext = namedtuple(
'TendermintContext', ('host', 'port', 'ws_url'))
return TendermintContext(
host=tendermint_host,
port=tendermint_port,
ws_url=tendermint_ws_url,
)
@pytest.fixture
def mocked_setup_pub_logger(mocker):
return mocker.patch(
'bigchaindb.log.setup.setup_pub_logger', autospec=True, spec_set=True)
@pytest.fixture
def mocked_setup_sub_logger(mocker):
return mocker.patch(
'bigchaindb.log.setup.setup_sub_logger', autospec=True, spec_set=True)
@pytest.fixture(autouse=True)
def _abci_http(request):
if request.keywords.get('abci', None):
@ -513,7 +416,7 @@ def abci_http(_setup_database, _configure_bigchaindb, abci_server,
@pytest.yield_fixture(scope='session')
def event_loop(request):
def event_loop():
import asyncio
loop = asyncio.get_event_loop_policy().new_event_loop()

View File

@ -8,12 +8,6 @@ import codecs
import abci.types_pb2 as types
@pytest.fixture
def b():
from bigchaindb import BigchainDB
return BigchainDB()
@pytest.fixture
def validator_pub_key():
return 'B0E42D2589A455EAD339A035D6CE1C8C3E25863F268120AA0162AD7D003A4014'

View File

@ -16,13 +16,12 @@ from io import BytesIO
@pytest.mark.tendermint
@pytest.mark.bdb
def test_app(tb, init_chain_request):
def test_app(b, init_chain_request):
from bigchaindb 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)

View File

@ -57,10 +57,9 @@ def test_asset_is_separated_from_transaciton(b):
@pytest.mark.bdb
def test_get_latest_block(tb):
def test_get_latest_block(b):
from bigchaindb.lib import Block
b = tb
for i in range(10):
app_hash = os.urandom(16).hex()
txn_id = os.urandom(16).hex()
@ -75,8 +74,8 @@ def test_get_latest_block(tb):
@pytest.mark.bdb
@patch('bigchaindb.backend.query.get_block', return_value=None)
@patch('bigchaindb.BigchainDB.get_latest_block', return_value={'height': 10})
def test_get_empty_block(_0, _1, tb):
assert tb.get_block(5) == {'height': 5, 'transactions': []}
def test_get_empty_block(_0, _1, b):
assert b.get_block(5) == {'height': 5, 'transactions': []}
def test_validation_error(b):
@ -172,15 +171,15 @@ def test_validator_updates(b, validator_pub_key):
@pytest.mark.bdb
def test_update_utxoset(tb, signed_create_tx, signed_transfer_tx, db_context):
def test_update_utxoset(b, signed_create_tx, signed_transfer_tx, db_context):
mongo_client = MongoClient(host=db_context.host, port=db_context.port)
tb.update_utxoset(signed_create_tx)
b.update_utxoset(signed_create_tx)
utxoset = mongo_client[db_context.name]['utxos']
assert utxoset.count() == 1
utxo = utxoset.find_one()
assert utxo['transaction_id'] == signed_create_tx.id
assert utxo['output_index'] == 0
tb.update_utxoset(signed_transfer_tx)
b.update_utxoset(signed_transfer_tx)
assert utxoset.count() == 1
utxo = utxoset.find_one()
assert utxo['transaction_id'] == signed_transfer_tx.id
@ -188,14 +187,14 @@ def test_update_utxoset(tb, signed_create_tx, signed_transfer_tx, db_context):
@pytest.mark.bdb
def test_store_transaction(mocker, tb, signed_create_tx,
def test_store_transaction(mocker, b, signed_create_tx,
signed_transfer_tx, db_context):
mocked_store_asset = mocker.patch('bigchaindb.backend.query.store_assets')
mocked_store_metadata = mocker.patch(
'bigchaindb.backend.query.store_metadatas')
mocked_store_transaction = mocker.patch(
'bigchaindb.backend.query.store_transactions')
tb.store_bulk_transactions([signed_create_tx])
b.store_bulk_transactions([signed_create_tx])
# mongo_client = MongoClient(host=db_context.host, port=db_context.port)
# utxoset = mongo_client[db_context.name]['utxos']
# assert utxoset.count() == 1
@ -204,40 +203,40 @@ def test_store_transaction(mocker, tb, signed_create_tx,
# assert utxo['output_index'] == 0
mocked_store_asset.assert_called_once_with(
tb.connection,
b.connection,
[{'id': signed_create_tx.id, 'data': signed_create_tx.asset['data']}],
)
mocked_store_metadata.assert_called_once_with(
tb.connection,
b.connection,
[{'id': signed_create_tx.id, 'metadata': signed_create_tx.metadata}],
)
mocked_store_transaction.assert_called_once_with(
tb.connection,
b.connection,
[{k: v for k, v in signed_create_tx.to_dict().items()
if k not in ('asset', 'metadata')}],
)
mocked_store_asset.reset_mock()
mocked_store_metadata.reset_mock()
mocked_store_transaction.reset_mock()
tb.store_bulk_transactions([signed_transfer_tx])
b.store_bulk_transactions([signed_transfer_tx])
# assert utxoset.count() == 1
# utxo = utxoset.find_one()
# assert utxo['transaction_id'] == signed_transfer_tx.id
# assert utxo['output_index'] == 0
assert not mocked_store_asset.called
mocked_store_metadata.asser_called_once_with(
tb.connection,
b.connection,
[{'id': signed_transfer_tx.id, 'metadata': signed_transfer_tx.metadata}],
)
mocked_store_transaction.assert_called_once_with(
tb.connection,
b.connection,
[{k: v for k, v in signed_transfer_tx.to_dict().items()
if k != 'metadata'}],
)
@pytest.mark.bdb
def test_store_bulk_transaction(mocker, tb, signed_create_tx,
def test_store_bulk_transaction(mocker, b, signed_create_tx,
signed_transfer_tx, db_context):
mocked_store_assets = mocker.patch(
'bigchaindb.backend.query.store_assets')
@ -245,7 +244,7 @@ def test_store_bulk_transaction(mocker, tb, signed_create_tx,
'bigchaindb.backend.query.store_metadatas')
mocked_store_transactions = mocker.patch(
'bigchaindb.backend.query.store_transactions')
tb.store_bulk_transactions((signed_create_tx,))
b.store_bulk_transactions((signed_create_tx,))
# mongo_client = MongoClient(host=db_context.host, port=db_context.port)
# utxoset = mongo_client[db_context.name]['utxos']
# assert utxoset.count() == 1
@ -253,34 +252,34 @@ def test_store_bulk_transaction(mocker, tb, signed_create_tx,
# assert utxo['transaction_id'] == signed_create_tx.id
# assert utxo['output_index'] == 0
mocked_store_assets.assert_called_once_with(
tb.connection,
b.connection,
[{'id': signed_create_tx.id, 'data': signed_create_tx.asset['data']}],
)
mocked_store_metadata.assert_called_once_with(
tb.connection,
b.connection,
[{'id': signed_create_tx.id, 'metadata': signed_create_tx.metadata}],
)
mocked_store_transactions.assert_called_once_with(
tb.connection,
b.connection,
[{k: v for k, v in signed_create_tx.to_dict().items()
if k not in ('asset', 'metadata')}],
)
mocked_store_assets.reset_mock()
mocked_store_metadata.reset_mock()
mocked_store_transactions.reset_mock()
tb.store_bulk_transactions((signed_transfer_tx,))
b.store_bulk_transactions((signed_transfer_tx,))
# assert utxoset.count() == 1
# utxo = utxoset.find_one()
# assert utxo['transaction_id'] == signed_transfer_tx.id
# assert utxo['output_index'] == 0
assert not mocked_store_assets.called
mocked_store_metadata.asser_called_once_with(
tb.connection,
b.connection,
[{'id': signed_transfer_tx.id,
'metadata': signed_transfer_tx.metadata}],
)
mocked_store_transactions.assert_called_once_with(
tb.connection,
b.connection,
[{k: v for k, v in signed_transfer_tx.to_dict().items()
if k != 'metadata'}],
)

View File

@ -24,7 +24,7 @@ def clean_config(monkeypatch, request):
monkeypatch.setattr('bigchaindb.config', original_config)
def test_bigchain_instance_is_initialized_when_conf_provided(request):
def test_bigchain_instance_is_initialized_when_conf_provided():
import bigchaindb
from bigchaindb import config_utils
assert 'CONFIGURED' not in bigchaindb.config

View File

@ -66,7 +66,6 @@ def test_bigchain_class_initialization_with_parameters():
assert bigchain.consensus == BaseConsensusRules
@pytest.mark.genesis
def test_get_spent_issue_1271(b, alice, bob, carol):
from bigchaindb.models import Transaction

View File

@ -23,8 +23,7 @@ def test_get_assets_with_missing_text_search(client):
@pytest.mark.bdb
@pytest.mark.tendermint
@pytest.mark.localmongodb
def test_get_assets_tendermint(client, tb, alice):
def test_get_assets_tendermint(client, b, alice):
from bigchaindb.models import Transaction
# test returns empty list when no assets are found
@ -37,7 +36,7 @@ def test_get_assets_tendermint(client, tb, alice):
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)],
asset=asset).sign([alice.private_key])
tb.store_bulk_transactions([tx])
b.store_bulk_transactions([tx])
# test that asset is returned
res = client.get(ASSETS_ENDPOINT + '?search=abc')
@ -51,11 +50,9 @@ def test_get_assets_tendermint(client, tb, alice):
@pytest.mark.bdb
@pytest.mark.tendermint
@pytest.mark.localmongodb
def test_get_assets_limit_tendermint(client, tb, alice):
def test_get_assets_limit_tendermint(client, b, alice):
from bigchaindb.models import Transaction
b = tb
# create two assets
asset1 = {'msg': 'abc 1'}
asset2 = {'msg': 'abc 2'}

View File

@ -14,9 +14,8 @@ pytestmark = pytest.mark.tendermint
@pytest.mark.bdb
@pytest.mark.usefixtures('inputs')
def test_get_block_endpoint(tb, client, alice):
def test_get_block_endpoint(b, client, alice):
import copy
b = tb
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'})
tx = tx.sign([alice.private_key])
@ -49,8 +48,7 @@ def test_get_block_returns_404_if_not_found(client):
@pytest.mark.bdb
def test_get_block_containing_transaction(tb, client, alice):
b = tb
def test_get_block_containing_transaction(b, client, alice):
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'})
tx = tx.sign([alice.private_key])
b.store_bulk_transactions([tx])

View File

@ -23,11 +23,9 @@ def test_get_metadata_with_missing_text_search(client):
@pytest.mark.bdb
@pytest.mark.tendermint
def test_get_metadata_tendermint(client, tb, alice):
def test_get_metadata_tendermint(client, b, alice):
from bigchaindb.models import Transaction
b = tb
# test returns empty list when no assets are found
res = client.get(METADATA_ENDPOINT + '?search=abc')
assert res.json == []
@ -53,11 +51,9 @@ def test_get_metadata_tendermint(client, tb, alice):
@pytest.mark.bdb
@pytest.mark.tendermint
def test_get_metadata_limit_tendermint(client, tb, alice):
def test_get_metadata_limit_tendermint(client, b, alice):
from bigchaindb.models import Transaction
b = tb
# create two assets
asset1 = {'msg': 'abc 1'}
meta1 = {'key': 'meta 1'}

View File

@ -4,6 +4,8 @@
import pytest
pytestmark = pytest.mark.tendermint
def test_valid_txid():
from bigchaindb.web.views.parameters import valid_txid

View File

@ -2,6 +2,10 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import pytest
pytestmark = pytest.mark.tendermint
def test_settings():
import bigchaindb

View File

@ -9,7 +9,7 @@ pytestmark = pytest.mark.tendermint
VALIDATORS_ENDPOINT = '/api/v1/validators/'
def test_get_validators_endpoint(b, client, monkeypatch):
def test_get_validators_endpoint(b, client):
validator_set = [{'address': 'F5426F0980E36E03044F74DD414248D29ABCBDB2',
'pub_key': {'data': '4E2685D9016126864733225BE00F005515200727FBAB1312FC78C8B76831255A',
'type': 'ed25519'},

View File

@ -21,6 +21,33 @@ class MockWebSocket:
self.received.append(s)
def test_eventify_block_works_with_any_transaction():
from bigchaindb.web.websocket_server import eventify_block
block = {
'height': 1,
'transactions': [{
'id': 1
}, {
'id': 2,
'asset': {'id': 1}
}]
}
expected_events = [{
'height': 1,
'asset_id': 1,
'transaction_id': 1
}, {
'height': 1,
'asset_id': 1,
'transaction_id': 2
}]
for event, expected in zip(eventify_block(block), expected_events):
assert event == expected
@asyncio.coroutine
def test_bridge_sync_async_queue(loop):
from bigchaindb.web.websocket_server import _multiprocessing_to_asyncio
@ -136,7 +163,6 @@ def test_websocket_block_event(b, test_client, loop):
@pytest.mark.skip('Processes are not stopping properly, and the whole test suite would hang')
@pytest.mark.genesis
def test_integration_from_webapi_to_websocket(monkeypatch, client, loop):
# XXX: I think that the `pytest-aiohttp` plugin is sparkling too much
# magic in the `asyncio` module: running this test without monkey-patching
@ -152,6 +178,8 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop):
import aiohttp
from bigchaindb.common import crypto
# TODO processes does not exist anymore, when reactivating this test it
# will fail because of this
from bigchaindb import processes
from bigchaindb.models import Transaction