mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: ValidatorElection.conclude not dependent on height
Solution: Height is an important factor when concluding an election during replay i.e. fetching the current validator set should be dependent on height
This commit is contained in:
parent
b2839668d6
commit
d2e71eaebc
@ -442,21 +442,6 @@ class BigchainDB(object):
|
|||||||
validators = result['validators']
|
validators = result['validators']
|
||||||
return validators
|
return validators
|
||||||
|
|
||||||
def get_validator_update(self, txns):
|
|
||||||
votes = {}
|
|
||||||
for txn in txns:
|
|
||||||
if isinstance(txn, ValidatorElectionVote):
|
|
||||||
election_id = txn.asset['id']
|
|
||||||
election_votes = votes.get(election_id, [])
|
|
||||||
votes[election_id] = election_votes.append(txn)
|
|
||||||
|
|
||||||
election = ValidatorElection.conclude(self, election_id, election_votes)
|
|
||||||
# Once an election concludes any other conclusion for the same
|
|
||||||
# or any other election is invalidated
|
|
||||||
if election:
|
|
||||||
return [election.asset['data']]
|
|
||||||
return []
|
|
||||||
|
|
||||||
def delete_validator_update(self):
|
def delete_validator_update(self):
|
||||||
return backend.query.delete_validator_update(self.connection)
|
return backend.query.delete_validator_update(self.connection)
|
||||||
|
|
||||||
|
|||||||
@ -33,13 +33,13 @@ class ValidatorElection(Transaction):
|
|||||||
super().__init__(operation, asset, inputs, outputs, metadata, version, hash_id)
|
super().__init__(operation, asset, inputs, outputs, metadata, version, hash_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def current_validators(cls, bigchain):
|
def current_validators(cls, bigchain, height=None):
|
||||||
"""Return a dictionary of validators with key as `public_key` and
|
"""Return a dictionary of validators with key as `public_key` and
|
||||||
value as the `voting_power`
|
value as the `voting_power`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
validators = {}
|
validators = {}
|
||||||
for validator in bigchain.get_validators():
|
for validator in bigchain.get_validators(height):
|
||||||
# NOTE: we assume that Tendermint encodes public key in base64
|
# NOTE: we assume that Tendermint encodes public key in base64
|
||||||
public_key = public_key_from_ed25519_key(key_from_base64(validator['pub_key']['data']))
|
public_key = public_key_from_ed25519_key(key_from_base64(validator['pub_key']['data']))
|
||||||
validators[public_key] = validator['voting_power']
|
validators[public_key] = validator['voting_power']
|
||||||
@ -183,7 +183,7 @@ class ValidatorElection(Transaction):
|
|||||||
return self.count_votes(election_pk, txns)
|
return self.count_votes(election_pk, txns)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def conclude(cls, bigchain, txn_id, current_votes=[]):
|
def conclude(cls, bigchain, txn_id, current_votes=[], height=None):
|
||||||
"""Check if the given election has concluded or not
|
"""Check if the given election has concluded or not
|
||||||
NOTE:
|
NOTE:
|
||||||
* Election is concluded iff the current validator set is exactly equal
|
* Election is concluded iff the current validator set is exactly equal
|
||||||
@ -196,7 +196,7 @@ class ValidatorElection(Transaction):
|
|||||||
election_pk = election.to_public_key(election.id)
|
election_pk = election.to_public_key(election.id)
|
||||||
votes_commited = election.get_commited_votes(bigchain, election_pk)
|
votes_commited = election.get_commited_votes(bigchain, election_pk)
|
||||||
votes_current = election.count_votes(election_pk, current_votes)
|
votes_current = election.count_votes(election_pk, current_votes)
|
||||||
current_validators = election.current_validators(bigchain)
|
current_validators = election.current_validators(bigchain, height)
|
||||||
|
|
||||||
if election.is_same_topology(current_validators, election.outputs):
|
if election.is_same_topology(current_validators, election.outputs):
|
||||||
total_votes = sum(current_validators.values())
|
total_votes = sum(current_validators.values())
|
||||||
@ -216,7 +216,7 @@ class ValidatorElection(Transaction):
|
|||||||
election_votes.append(txn)
|
election_votes.append(txn)
|
||||||
votes[election_id] = election_votes
|
votes[election_id] = election_votes
|
||||||
|
|
||||||
election = cls.conclude(bigchain, election_id, election_votes)
|
election = cls.conclude(bigchain, election_id, election_votes, new_height)
|
||||||
# Once an election concludes any other conclusion for the same
|
# Once an election concludes any other conclusion for the same
|
||||||
# or any other election is invalidated
|
# or any other election is invalidated
|
||||||
if election:
|
if election:
|
||||||
|
|||||||
@ -384,7 +384,7 @@ def test_upsert_validator_new_with_tendermint(b, priv_validator_path, user_sk, m
|
|||||||
def test_upsert_validator_new_without_tendermint(b, priv_validator_path, user_sk, monkeypatch):
|
def test_upsert_validator_new_without_tendermint(b, priv_validator_path, user_sk, monkeypatch):
|
||||||
from bigchaindb.commands.bigchaindb import run_upsert_validator_new
|
from bigchaindb.commands.bigchaindb import run_upsert_validator_new
|
||||||
|
|
||||||
def mock_get():
|
def mock_get(height):
|
||||||
return [
|
return [
|
||||||
{'pub_key': {'data': 'zL/DasvKulXZzhSNFwx4cLRXKkSM9GPK7Y0nZ4FEylM=',
|
{'pub_key': {'data': 'zL/DasvKulXZzhSNFwx4cLRXKkSM9GPK7Y0nZ4FEylM=',
|
||||||
'type': 'tendermint/PubKeyEd25519'},
|
'type': 'tendermint/PubKeyEd25519'},
|
||||||
|
|||||||
@ -22,7 +22,7 @@ def new_validator():
|
|||||||
|
|
||||||
|
|
||||||
def mock_get_validators(network_validators):
|
def mock_get_validators(network_validators):
|
||||||
def validator_set():
|
def validator_set(height):
|
||||||
validators = []
|
validators = []
|
||||||
for public_key, power in network_validators.items():
|
for public_key, power in network_validators.items():
|
||||||
validators.append({
|
validators.append({
|
||||||
|
|||||||
@ -194,30 +194,6 @@ def test_valid_election_conclude(b_mock, valid_election, ed25519_node_keys):
|
|||||||
assert not ValidatorElection.conclude(b_mock, valid_election.id, [tx_vote3])
|
assert not ValidatorElection.conclude(b_mock, valid_election.id, [tx_vote3])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.tendermint
|
|
||||||
@pytest.mark.bdb
|
|
||||||
def test_get_validator_update_conclude(b_mock, valid_election, ed25519_node_keys):
|
|
||||||
# store election
|
|
||||||
b_mock.store_bulk_transactions([valid_election])
|
|
||||||
|
|
||||||
# Node 0: cast vote
|
|
||||||
tx_vote0 = gen_vote(valid_election, 0, ed25519_node_keys)
|
|
||||||
assert b_mock.get_validator_update([tx_vote0]) == []
|
|
||||||
b_mock.store_bulk_transactions([tx_vote0])
|
|
||||||
|
|
||||||
tx_vote1 = gen_vote(valid_election, 1, ed25519_node_keys)
|
|
||||||
assert b_mock.get_validator_update([tx_vote1]) == []
|
|
||||||
b_mock.store_bulk_transactions([tx_vote1])
|
|
||||||
|
|
||||||
# Election can only be concluded once
|
|
||||||
tx_vote2 = gen_vote(valid_election, 2, ed25519_node_keys)
|
|
||||||
assert b_mock.get_validator_update([tx_vote2]) == [valid_election.asset['data']]
|
|
||||||
b_mock.store_bulk_transactions([tx_vote2])
|
|
||||||
|
|
||||||
tx_vote3 = gen_vote(valid_election, 3, ed25519_node_keys)
|
|
||||||
assert b_mock.get_validator_update([tx_vote3]) == []
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.abci
|
@pytest.mark.abci
|
||||||
def test_upsert_validator(b, node_key, node_keys, new_validator, ed25519_node_keys):
|
def test_upsert_validator(b, node_key, node_keys, new_validator, ed25519_node_keys):
|
||||||
import time
|
import time
|
||||||
@ -292,12 +268,24 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys):
|
|||||||
tx_vote1 = gen_vote(election, 1, ed25519_node_keys)
|
tx_vote1 = gen_vote(election, 1, ed25519_node_keys)
|
||||||
tx_vote2 = gen_vote(election, 2, ed25519_node_keys)
|
tx_vote2 = gen_vote(election, 2, ed25519_node_keys)
|
||||||
|
|
||||||
|
assert not ValidatorElection.conclude(b, election.id, [tx_vote0])
|
||||||
|
assert not ValidatorElection.conclude(b, election.id, [tx_vote0, tx_vote1])
|
||||||
assert ValidatorElection.conclude(b, election.id, [tx_vote0, tx_vote1, tx_vote2])
|
assert ValidatorElection.conclude(b, election.id, [tx_vote0, tx_vote1, tx_vote2])
|
||||||
|
|
||||||
update = ValidatorElection.get_validator_update(b, 4, [tx_vote0, tx_vote1, tx_vote2])
|
assert ValidatorElection.get_validator_update(b, 4, [tx_vote0]) == []
|
||||||
|
assert ValidatorElection.get_validator_update(b, 4, [tx_vote0, tx_vote1]) == []
|
||||||
|
|
||||||
assert len(update) == 1
|
update = ValidatorElection.get_validator_update(b, 4, [tx_vote0, tx_vote1, tx_vote2])
|
||||||
update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n')
|
update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n')
|
||||||
|
assert len(update) == 1
|
||||||
|
assert update_public_key == public_key64
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_vote0, tx_vote1])
|
||||||
|
|
||||||
|
update = ValidatorElection.get_validator_update(b, 4, [tx_vote2])
|
||||||
|
print('update', update)
|
||||||
|
update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n')
|
||||||
|
assert len(update) == 1
|
||||||
assert update_public_key == public_key64
|
assert update_public_key == public_key64
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user