mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: Validator set not tracked by BigchainDB (#2436)
* Problem: Validator set not tracked by BigchainDB Solution: BigchainDB depends on tendermint's RPC API to get the validator set which is not avaiable during replay so the validators set should be tracked inside BigchainDB * Problem: Unclear code and documentation Solution: Fix decode_validator and docs strings * Problem: Doc strings missing Solution: Add doc string for store_validato_set
This commit is contained in:
parent
e0676306b7
commit
2e9a9b1121
@ -8,7 +8,6 @@ from bigchaindb.common.exceptions import MultipleValidatorOperationError
|
|||||||
from bigchaindb.backend.utils import module_dispatch_registrar
|
from bigchaindb.backend.utils import module_dispatch_registrar
|
||||||
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
|
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
|
||||||
from bigchaindb.common.transaction import Transaction
|
from bigchaindb.common.transaction import Transaction
|
||||||
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
|
||||||
|
|
||||||
register_query = module_dispatch_registrar(backend.query)
|
register_query = module_dispatch_registrar(backend.query)
|
||||||
|
|
||||||
@ -279,7 +278,7 @@ def get_pre_commit_state(conn, commit_id):
|
|||||||
|
|
||||||
|
|
||||||
@register_query(LocalMongoDBConnection)
|
@register_query(LocalMongoDBConnection)
|
||||||
def store_validator_update(conn, validator_update):
|
def store_validator_set(conn, validator_update):
|
||||||
try:
|
try:
|
||||||
return conn.run(
|
return conn.run(
|
||||||
conn.collection('validators')
|
conn.collection('validators')
|
||||||
@ -289,15 +288,16 @@ def store_validator_update(conn, validator_update):
|
|||||||
|
|
||||||
|
|
||||||
@register_query(LocalMongoDBConnection)
|
@register_query(LocalMongoDBConnection)
|
||||||
def get_validator_update(conn, update_id=VALIDATOR_UPDATE_ID):
|
def get_validator_set(conn, height=None):
|
||||||
return conn.run(
|
query = {}
|
||||||
conn.collection('validators')
|
if height is not None:
|
||||||
.find_one({'update_id': update_id}, projection={'_id': False}))
|
query = {'height': {'$lte': height}}
|
||||||
|
|
||||||
|
cursor = conn.run(
|
||||||
@register_query(LocalMongoDBConnection)
|
|
||||||
def delete_validator_update(conn, update_id=VALIDATOR_UPDATE_ID):
|
|
||||||
return conn.run(
|
|
||||||
conn.collection('validators')
|
conn.collection('validators')
|
||||||
.delete_one({'update_id': update_id})
|
.find(query, projection={'_id': False})
|
||||||
|
.sort([('height', DESCENDING)])
|
||||||
|
.limit(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return list(cursor)[0]
|
||||||
|
@ -126,6 +126,6 @@ def create_pre_commit_secondary_index(conn, dbname):
|
|||||||
def create_validators_secondary_index(conn, dbname):
|
def create_validators_secondary_index(conn, dbname):
|
||||||
logger.info('Create `validators` secondary index.')
|
logger.info('Create `validators` secondary index.')
|
||||||
|
|
||||||
conn.conn[dbname]['validators'].create_index('update_id',
|
conn.conn[dbname]['validators'].create_index('height',
|
||||||
name='update_id',
|
name='height',
|
||||||
unique=True,)
|
unique=True,)
|
||||||
|
@ -340,13 +340,6 @@ def store_pre_commit_state(connection, commit_id, state):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
|
||||||
def store_validator_update(conn, validator_update):
|
|
||||||
"""Store a update for the validator set"""
|
|
||||||
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def get_pre_commit_state(connection, commit_id):
|
def get_pre_commit_state(connection, commit_id):
|
||||||
"""Get pre-commit state where `id` is `commit_id`.
|
"""Get pre-commit state where `id` is `commit_id`.
|
||||||
@ -362,14 +355,15 @@ def get_pre_commit_state(connection, commit_id):
|
|||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def get_validator_update(conn):
|
def store_validator_set(conn, validator_update):
|
||||||
"""Get validator updates which are not synced"""
|
"""Store updated validator set"""
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def delete_validator_update(conn, id):
|
def get_validator_set(conn, height):
|
||||||
"""Set the sync status for validator update documents"""
|
"""Get validator set for a given `height`, if `height` is not specified
|
||||||
|
then return the latest validator set"""
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""This module contains all the goodness to integrate BigchainDB
|
"""This module contains all the goodness to integrate BigchainDB
|
||||||
with Tendermint."""
|
with Tendermint."""
|
||||||
import logging
|
import logging
|
||||||
|
import codecs
|
||||||
|
|
||||||
from abci.application import BaseApplication
|
from abci.application import BaseApplication
|
||||||
from abci.types_pb2 import (
|
from abci.types_pb2 import (
|
||||||
@ -42,11 +43,13 @@ class App(BaseApplication):
|
|||||||
self.validators = None
|
self.validators = None
|
||||||
self.new_height = None
|
self.new_height = None
|
||||||
|
|
||||||
def init_chain(self, validators):
|
def init_chain(self, genesis):
|
||||||
"""Initialize chain with block of height 0"""
|
"""Initialize chain with block of height 0"""
|
||||||
|
|
||||||
|
validator_set = [decode_validator(v) for v in genesis.validators]
|
||||||
block = Block(app_hash='', height=0, transactions=[])
|
block = Block(app_hash='', height=0, transactions=[])
|
||||||
self.bigchaindb.store_block(block._asdict())
|
self.bigchaindb.store_block(block._asdict())
|
||||||
|
self.bigchaindb.store_validator_set(1, validator_set)
|
||||||
return ResponseInitChain()
|
return ResponseInitChain()
|
||||||
|
|
||||||
def info(self, request):
|
def info(self, request):
|
||||||
@ -129,11 +132,11 @@ class App(BaseApplication):
|
|||||||
else:
|
else:
|
||||||
self.block_txn_hash = block['app_hash']
|
self.block_txn_hash = block['app_hash']
|
||||||
|
|
||||||
validator_updates = self.bigchaindb.get_validator_update()
|
# TODO: calculate if an election has concluded
|
||||||
validator_updates = [encode_validator(v) for v in validator_updates]
|
# NOTE: ensure the local validator set is updated
|
||||||
|
# validator_updates = self.bigchaindb.get_validator_update()
|
||||||
# set sync status to true
|
# validator_updates = [encode_validator(v) for v in validator_updates]
|
||||||
self.bigchaindb.delete_validator_update()
|
validator_updates = []
|
||||||
|
|
||||||
# Store pre-commit state to recover in case there is a crash
|
# Store pre-commit state to recover in case there is a crash
|
||||||
# during `commit`
|
# during `commit`
|
||||||
@ -176,3 +179,10 @@ def encode_validator(v):
|
|||||||
return Validator(pub_key=pub_key,
|
return Validator(pub_key=pub_key,
|
||||||
address=b'',
|
address=b'',
|
||||||
power=v['power'])
|
power=v['power'])
|
||||||
|
|
||||||
|
|
||||||
|
def decode_validator(v):
|
||||||
|
return {'address': codecs.encode(v.address, 'hex').decode().upper().rstrip('\n'),
|
||||||
|
'pub_key': {'type': v.pub_key.type,
|
||||||
|
'data': codecs.encode(v.pub_key.data, 'base64').decode().rstrip('\n')},
|
||||||
|
'voting_power': v.power}
|
||||||
|
@ -460,20 +460,14 @@ class BigchainDB(object):
|
|||||||
def fastquery(self):
|
def fastquery(self):
|
||||||
return fastquery.FastQuery(self.connection)
|
return fastquery.FastQuery(self.connection)
|
||||||
|
|
||||||
def get_validators(self):
|
def get_validators(self, height=None):
|
||||||
try:
|
result = backend.query.get_validator_set(self.connection, height)
|
||||||
resp = requests.get('{}validators'.format(self.endpoint))
|
validators = result['validators']
|
||||||
validators = resp.json()['result']['validators']
|
|
||||||
for v in validators:
|
for v in validators:
|
||||||
v.pop('accum')
|
|
||||||
v.pop('address')
|
v.pop('address')
|
||||||
|
|
||||||
return validators
|
return validators
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
logger.error('Error while connecting to Tendermint HTTP API')
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def get_validator_update(self):
|
def get_validator_update(self):
|
||||||
update = backend.query.get_validator_update(self.connection)
|
update = backend.query.get_validator_update(self.connection)
|
||||||
return [update['validator']] if update else []
|
return [update['validator']] if update else []
|
||||||
@ -484,6 +478,14 @@ class BigchainDB(object):
|
|||||||
def store_pre_commit_state(self, state):
|
def store_pre_commit_state(self, state):
|
||||||
return backend.query.store_pre_commit_state(self.connection, state)
|
return backend.query.store_pre_commit_state(self.connection, state)
|
||||||
|
|
||||||
|
def store_validator_set(self, height, validators):
|
||||||
|
"""Store validator set at a given `height`.
|
||||||
|
NOTE: If the validator set already exists at that `height` then an
|
||||||
|
exception will be raised.
|
||||||
|
"""
|
||||||
|
return backend.query.store_validator_set(self.connection, {'height': height,
|
||||||
|
'validators': validators})
|
||||||
|
|
||||||
|
|
||||||
Block = namedtuple('Block', ('app_hash', 'height', 'transactions'))
|
Block = namedtuple('Block', ('app_hash', 'height', 'transactions'))
|
||||||
|
|
||||||
|
@ -370,22 +370,23 @@ def test_get_pre_commit_state(db_context):
|
|||||||
assert resp == state._asdict()
|
assert resp == state._asdict()
|
||||||
|
|
||||||
|
|
||||||
def test_store_validator_update():
|
def test_validator_update():
|
||||||
from bigchaindb.backend import connect, query
|
from bigchaindb.backend import connect, query
|
||||||
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
|
||||||
from bigchaindb.common.exceptions import MultipleValidatorOperationError
|
|
||||||
|
|
||||||
conn = connect()
|
conn = connect()
|
||||||
|
|
||||||
validator_update = {'validator': {'key': 'value'},
|
def gen_validator_update(height):
|
||||||
'update_id': VALIDATOR_UPDATE_ID}
|
return {'data': 'somedata', 'height': height}
|
||||||
query.store_validator_update(conn, deepcopy(validator_update))
|
|
||||||
|
|
||||||
with pytest.raises(MultipleValidatorOperationError):
|
for i in range(1, 100, 10):
|
||||||
query.store_validator_update(conn, deepcopy(validator_update))
|
value = gen_validator_update(i)
|
||||||
|
query.store_validator_set(conn, value)
|
||||||
|
|
||||||
resp = query.get_validator_update(conn, VALIDATOR_UPDATE_ID)
|
v1 = query.get_validator_set(conn, 8)
|
||||||
|
assert v1['height'] == 1
|
||||||
|
|
||||||
assert resp == validator_update
|
v41 = query.get_validator_set(conn, 50)
|
||||||
assert query.delete_validator_update(conn, VALIDATOR_UPDATE_ID)
|
assert v41['height'] == 41
|
||||||
assert not query.get_validator_update(conn, VALIDATOR_UPDATE_ID)
|
|
||||||
|
v91 = query.get_validator_set(conn)
|
||||||
|
assert v91['height'] == 91
|
||||||
|
@ -40,7 +40,7 @@ def test_init_creates_db_tables_and_indexes():
|
|||||||
assert set(indexes) == {'_id_', 'pre_commit_id'}
|
assert set(indexes) == {'_id_', 'pre_commit_id'}
|
||||||
|
|
||||||
indexes = conn.conn[dbname]['validators'].index_information().keys()
|
indexes = conn.conn[dbname]['validators'].index_information().keys()
|
||||||
assert set(indexes) == {'_id_', 'update_id'}
|
assert set(indexes) == {'_id_', 'height'}
|
||||||
|
|
||||||
|
|
||||||
def test_init_database_fails_if_db_exists():
|
def test_init_database_fails_if_db_exists():
|
||||||
|
@ -341,6 +341,7 @@ class MockResponse():
|
|||||||
return {'result': {'latest_block_height': self.height}}
|
return {'result': {'latest_block_height': self.height}}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
@patch('bigchaindb.config_utils.autoconfigure')
|
@patch('bigchaindb.config_utils.autoconfigure')
|
||||||
@patch('bigchaindb.backend.query.store_validator_update')
|
@patch('bigchaindb.backend.query.store_validator_update')
|
||||||
@pytest.mark.tendermint
|
@pytest.mark.tendermint
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
import abci.types_pb2 as types
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -10,3 +13,13 @@ def b():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def validator_pub_key():
|
def validator_pub_key():
|
||||||
return 'B0E42D2589A455EAD339A035D6CE1C8C3E25863F268120AA0162AD7D003A4014'
|
return 'B0E42D2589A455EAD339A035D6CE1C8C3E25863F268120AA0162AD7D003A4014'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def init_chain_request():
|
||||||
|
addr = codecs.decode(b'9FD479C869C7D7E7605BF99293457AA5D80C3033', 'hex')
|
||||||
|
pk = codecs.decode(b'VAgFZtYw8bNR5TMZHFOBDWk9cAmEu3/c6JgRBmddbbI=', 'base64')
|
||||||
|
val_a = types.Validator(address=addr, power=10,
|
||||||
|
pub_key=types.PubKey(type='ed25519', data=pk))
|
||||||
|
|
||||||
|
return types.RequestInitChain(validators=[val_a])
|
||||||
|
@ -50,7 +50,7 @@ def test_check_tx__unsigned_create_is_error(b):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_deliver_tx__valid_create_updates_db(b):
|
def test_deliver_tx__valid_create_updates_db(b, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.common.crypto import generate_key_pair
|
from bigchaindb.common.crypto import generate_key_pair
|
||||||
@ -64,8 +64,9 @@ def test_deliver_tx__valid_create_updates_db(b):
|
|||||||
|
|
||||||
app = App(b)
|
app = App(b)
|
||||||
|
|
||||||
|
app.init_chain(init_chain_request)
|
||||||
|
|
||||||
begin_block = RequestBeginBlock()
|
begin_block = RequestBeginBlock()
|
||||||
app.init_chain(['ignore'])
|
|
||||||
app.begin_block(begin_block)
|
app.begin_block(begin_block)
|
||||||
|
|
||||||
result = app.deliver_tx(encode_tx_to_bytes(tx))
|
result = app.deliver_tx(encode_tx_to_bytes(tx))
|
||||||
@ -83,7 +84,7 @@ def test_deliver_tx__valid_create_updates_db(b):
|
|||||||
# next(unspent_outputs)
|
# next(unspent_outputs)
|
||||||
|
|
||||||
|
|
||||||
def test_deliver_tx__double_spend_fails(b):
|
def test_deliver_tx__double_spend_fails(b, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.common.crypto import generate_key_pair
|
from bigchaindb.common.crypto import generate_key_pair
|
||||||
@ -96,7 +97,7 @@ def test_deliver_tx__double_spend_fails(b):
|
|||||||
.sign([alice.private_key])
|
.sign([alice.private_key])
|
||||||
|
|
||||||
app = App(b)
|
app = App(b)
|
||||||
app.init_chain(['ignore'])
|
app.init_chain(init_chain_request)
|
||||||
|
|
||||||
begin_block = RequestBeginBlock()
|
begin_block = RequestBeginBlock()
|
||||||
app.begin_block(begin_block)
|
app.begin_block(begin_block)
|
||||||
@ -112,13 +113,13 @@ def test_deliver_tx__double_spend_fails(b):
|
|||||||
assert result.code == CodeTypeError
|
assert result.code == CodeTypeError
|
||||||
|
|
||||||
|
|
||||||
def test_deliver_transfer_tx__double_spend_fails(b):
|
def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.common.crypto import generate_key_pair
|
from bigchaindb.common.crypto import generate_key_pair
|
||||||
|
|
||||||
app = App(b)
|
app = App(b)
|
||||||
app.init_chain(['ignore'])
|
app.init_chain(init_chain_request)
|
||||||
|
|
||||||
begin_block = RequestBeginBlock()
|
begin_block = RequestBeginBlock()
|
||||||
app.begin_block(begin_block)
|
app.begin_block(begin_block)
|
||||||
@ -156,14 +157,16 @@ def test_deliver_transfer_tx__double_spend_fails(b):
|
|||||||
assert result.code == CodeTypeError
|
assert result.code == CodeTypeError
|
||||||
|
|
||||||
|
|
||||||
def test_end_block_return_validator_updates(b):
|
# The test below has to re-written one election conclusion logic has been implemented
|
||||||
|
@pytest.mark.skip
|
||||||
|
def test_end_block_return_validator_updates(b, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.backend import query
|
from bigchaindb.backend import query
|
||||||
from bigchaindb.core import encode_validator
|
from bigchaindb.core import encode_validator
|
||||||
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
||||||
|
|
||||||
app = App(b)
|
app = App(b)
|
||||||
app.init_chain(['ignore'])
|
app.init_chain(init_chain_request)
|
||||||
|
|
||||||
begin_block = RequestBeginBlock()
|
begin_block = RequestBeginBlock()
|
||||||
app.begin_block(begin_block)
|
app.begin_block(begin_block)
|
||||||
@ -182,7 +185,7 @@ def test_end_block_return_validator_updates(b):
|
|||||||
assert updates == []
|
assert updates == []
|
||||||
|
|
||||||
|
|
||||||
def test_store_pre_commit_state_in_end_block(b, alice):
|
def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.backend import query
|
from bigchaindb.backend import query
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
@ -194,7 +197,7 @@ def test_store_pre_commit_state_in_end_block(b, alice):
|
|||||||
.sign([alice.private_key])
|
.sign([alice.private_key])
|
||||||
|
|
||||||
app = App(b)
|
app = App(b)
|
||||||
app.init_chain(['ignore'])
|
app.init_chain(init_chain_request)
|
||||||
|
|
||||||
begin_block = RequestBeginBlock()
|
begin_block = RequestBeginBlock()
|
||||||
app.begin_block(begin_block)
|
app.begin_block(begin_block)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import codecs
|
||||||
|
|
||||||
import abci.types_pb2 as types
|
import abci.types_pb2 as types
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
@ -11,7 +13,7 @@ from io import BytesIO
|
|||||||
|
|
||||||
@pytest.mark.tendermint
|
@pytest.mark.tendermint
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_app(tb):
|
def test_app(tb, init_chain_request):
|
||||||
from bigchaindb import App
|
from bigchaindb import App
|
||||||
from bigchaindb.tendermint_utils import calculate_hash
|
from bigchaindb.tendermint_utils import calculate_hash
|
||||||
from bigchaindb.common.crypto import generate_key_pair
|
from bigchaindb.common.crypto import generate_key_pair
|
||||||
@ -28,12 +30,17 @@ def test_app(tb):
|
|||||||
assert res.info.last_block_height == 0
|
assert res.info.last_block_height == 0
|
||||||
assert not b.get_latest_block()
|
assert not b.get_latest_block()
|
||||||
|
|
||||||
p.process('init_chain', types.Request(init_chain=types.RequestInitChain()))
|
p.process('init_chain', types.Request(init_chain=init_chain_request))
|
||||||
block0 = b.get_latest_block()
|
block0 = b.get_latest_block()
|
||||||
assert block0
|
assert block0
|
||||||
assert block0['height'] == 0
|
assert block0['height'] == 0
|
||||||
assert block0['app_hash'] == ''
|
assert block0['app_hash'] == ''
|
||||||
|
|
||||||
|
pk = codecs.encode(init_chain_request.validators[0].pub_key.data, 'base64').decode().strip('\n')
|
||||||
|
[validator] = b.get_validators(height=1)
|
||||||
|
assert validator['pub_key']['data'] == pk
|
||||||
|
assert validator['voting_power'] == 10
|
||||||
|
|
||||||
alice = generate_key_pair()
|
alice = generate_key_pair()
|
||||||
bob = generate_key_pair()
|
bob = generate_key_pair()
|
||||||
tx = Transaction.create([alice.public_key],
|
tx = Transaction.create([alice.public_key],
|
||||||
@ -98,6 +105,7 @@ def test_app(tb):
|
|||||||
assert block0['app_hash'] == new_block_hash
|
assert block0['app_hash'] == new_block_hash
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
@pytest.mark.abci
|
@pytest.mark.abci
|
||||||
def test_upsert_validator(b, alice):
|
def test_upsert_validator(b, alice):
|
||||||
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
from bigchaindb.backend.query import VALIDATOR_UPDATE_ID
|
||||||
|
@ -139,6 +139,7 @@ def test_post_transaction_invalid_mode(b):
|
|||||||
b.write_transaction(tx, 'nope')
|
b.write_transaction(tx, 'nope')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_validator_updates(b, validator_pub_key):
|
def test_validator_updates(b, validator_pub_key):
|
||||||
from bigchaindb.backend import query
|
from bigchaindb.backend import query
|
||||||
|
@ -1,49 +1,22 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from requests.exceptions import RequestException
|
|
||||||
|
|
||||||
pytestmark = pytest.mark.tendermint
|
pytestmark = pytest.mark.tendermint
|
||||||
|
|
||||||
VALIDATORS_ENDPOINT = '/api/v1/validators/'
|
VALIDATORS_ENDPOINT = '/api/v1/validators/'
|
||||||
|
|
||||||
|
|
||||||
def test_get_validators_endpoint(b, client, monkeypatch):
|
def test_get_validators_endpoint(b, client, monkeypatch):
|
||||||
|
validator_set = [{'address': 'F5426F0980E36E03044F74DD414248D29ABCBDB2',
|
||||||
def mock_get(uri):
|
'pub_key': {'data': '4E2685D9016126864733225BE00F005515200727FBAB1312FC78C8B76831255A',
|
||||||
return MockResponse()
|
'type': 'ed25519'},
|
||||||
monkeypatch.setattr('requests.get', mock_get)
|
'voting_power': 10}]
|
||||||
|
b.store_validator_set(23, validator_set)
|
||||||
|
|
||||||
res = client.get(VALIDATORS_ENDPOINT)
|
res = client.get(VALIDATORS_ENDPOINT)
|
||||||
|
|
||||||
assert is_validator(res.json[0])
|
assert is_validator(res.json[0])
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
def test_get_validators_500_endpoint(b, client, monkeypatch):
|
|
||||||
|
|
||||||
def mock_get(uri):
|
|
||||||
raise RequestException
|
|
||||||
monkeypatch.setattr('requests.get', mock_get)
|
|
||||||
|
|
||||||
with pytest.raises(RequestException):
|
|
||||||
client.get(VALIDATORS_ENDPOINT)
|
|
||||||
|
|
||||||
|
|
||||||
# Helper
|
# Helper
|
||||||
def is_validator(v):
|
def is_validator(v):
|
||||||
return ('pub_key' in v) and ('voting_power' in v)
|
return ('pub_key' in v) and ('voting_power' in v)
|
||||||
|
|
||||||
|
|
||||||
class MockResponse():
|
|
||||||
|
|
||||||
def json(self):
|
|
||||||
return {'id': '',
|
|
||||||
'jsonrpc': '2.0',
|
|
||||||
'result':
|
|
||||||
{'block_height': 5,
|
|
||||||
'validators': [
|
|
||||||
{'accum': 0,
|
|
||||||
'address': 'F5426F0980E36E03044F74DD414248D29ABCBDB2',
|
|
||||||
'pub_key': {'data': '4E2685D9016126864733225BE00F005515200727FBAB1312FC78C8B76831255A',
|
|
||||||
'type': 'ed25519'},
|
|
||||||
'voting_power': 10}]}}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user