mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
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
This commit is contained in:
parent
d25d806cd8
commit
91c8a4528b
@ -8,7 +8,7 @@ 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 +279,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 +289,14 @@ 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):
|
||||||
|
query = {}
|
||||||
|
if height is not None:
|
||||||
|
query = {'height': {'$lte': height}}
|
||||||
|
|
||||||
return conn.run(
|
return conn.run(
|
||||||
conn.collection('validators')
|
conn.collection('validators')
|
||||||
.find_one({'update_id': update_id}, projection={'_id': False}))
|
.find(query, projection={'_id': False})
|
||||||
|
.sort([('height', DESCENDING)])
|
||||||
|
.limit(1)
|
||||||
@register_query(LocalMongoDBConnection)
|
|
||||||
def delete_validator_update(conn, update_id=VALIDATOR_UPDATE_ID):
|
|
||||||
return conn.run(
|
|
||||||
conn.collection('validators')
|
|
||||||
.delete_one({'update_id': update_id})
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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,14 @@ 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 at which are not synced"""
|
||||||
|
|
||||||
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,12 @@ 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):
|
||||||
|
validator = {'address': '', 'pub_key': {'type': '', 'data': ''}, 'voting_power': 0}
|
||||||
|
validator['address'] = codecs.encode(v.address, 'hex').decode().upper().rstrip('\n')
|
||||||
|
validator['pub_key']['type'] = v.pub_key.type
|
||||||
|
validator['pub_key']['data'] = codecs.encode(v.pub_key.data, 'base64').decode().rstrip('\n')
|
||||||
|
validator['voting_power'] = v.power
|
||||||
|
return validator
|
||||||
|
|||||||
@ -460,19 +460,13 @@ 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 = list(backend.query.get_validator_set(self.connection, height))[0]
|
||||||
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('address')
|
||||||
v.pop('accum')
|
|
||||||
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)
|
||||||
@ -484,6 +478,10 @@ 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):
|
||||||
|
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] = list(query.get_validator_set(conn, 8))
|
||||||
|
assert v1['height'] == 1
|
||||||
|
|
||||||
assert resp == validator_update
|
[v41] = list(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] = list(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