From 3d67565bda769031e4ea883227863d16b9e35759 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Fri, 31 Aug 2018 13:56:55 +0200 Subject: [PATCH 01/13] Problem: `ValidatorElection` and `MigrationElection` need to inherit from a common `Election` class Solution: Factored the common logic out of `ValidatorElection` and moved it to `Election` parent class --- bigchaindb/__init__.py | 2 +- bigchaindb/backend/localmongodb/query.py | 4 +- bigchaindb/backend/query.py | 6 +- bigchaindb/common/election.py | 248 +++++++++++++++++ bigchaindb/core.py | 6 +- bigchaindb/lib.py | 7 +- .../upsert_validator/validator_election.py | 257 ++---------------- setup.py | 2 +- tests/tendermint/test_core.py | 2 +- tests/tendermint/test_lib.py | 4 +- .../test_validator_election_vote.py | 10 +- 11 files changed, 292 insertions(+), 256 deletions(-) create mode 100644 bigchaindb/common/election.py diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index 5e69b684..b936d8aa 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -98,5 +98,5 @@ from bigchaindb.upsert_validator import ValidatorElectionVote # noqa Transaction.register_type(Transaction.CREATE, models.Transaction) Transaction.register_type(Transaction.TRANSFER, models.Transaction) -Transaction.register_type(ValidatorElection.VALIDATOR_ELECTION, ValidatorElection) +Transaction.register_type(ValidatorElection.ELECTION_TYPE, ValidatorElection) Transaction.register_type(ValidatorElectionVote.VALIDATOR_ELECTION_VOTE, ValidatorElectionVote) diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 29993b30..4e4557c8 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -300,11 +300,11 @@ def get_validator_set(conn, height=None): @register_query(LocalMongoDBConnection) -def get_validator_set_by_election_id(conn, election_id): +def get_result_by_election_id(conn, election_id, table): query = {'election_id': election_id} cursor = conn.run( - conn.collection('validators') + conn.collection(table) .find(query, projection={'_id': False}) ) diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 4d62c633..86028a05 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -361,7 +361,7 @@ def get_validator_set(conn, height): @singledispatch -def get_validator_set_by_election_id(conn, election_id): +def get_result_by_election_id(conn, election_id, table): """Return a validator set change with the specified election_id """ @@ -369,13 +369,11 @@ def get_validator_set_by_election_id(conn, election_id): @singledispatch -def get_asset_tokens_for_public_key(connection, asset_id, - public_key, operation): +def get_asset_tokens_for_public_key(connection, asset_id, public_key): """Retrieve a list of tokens of type `asset_id` that are owned by the `public_key`. Args: asset_id (str): Id of the token. public_key (str): base58 encoded public key - operation: filter transaction based on `operation` Returns: Iterator of transaction that list given owner in conditions. """ diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py new file mode 100644 index 00000000..e114a6c6 --- /dev/null +++ b/bigchaindb/common/election.py @@ -0,0 +1,248 @@ +# Copyright BigchainDB GmbH and BigchainDB contributors +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import base58 + +from bigchaindb import backend +from bigchaindb.common.exceptions import (InvalidSignature, + MultipleInputsError, + InvalidProposer, + UnequalValidatorSet, + DuplicateTransaction) +from bigchaindb.tendermint_utils import key_from_base64 +from bigchaindb.common.crypto import (public_key_from_ed25519_key) +from bigchaindb.common.transaction import Transaction +from bigchaindb.common.schema import (_validate_schema, + TX_SCHEMA_COMMON, + TX_SCHEMA_CREATE) + + +class Election(Transaction): + + # NOTE: this transaction class extends create so the operation inheritance is achieved + # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) + ELECTION_TYPE = None + # the name of the mongodb table managed by the election + DB_TABLE = None + # the model for votes issued by the election + VOTE_TYPE = None + # Election Statuses: + ONGOING = 'ongoing' + CONCLUDED = 'concluded' + INCONCLUSIVE = 'inconclusive' + # Vote ratio to approve an election + ELECTION_THRESHOLD = 2 / 3 + + @classmethod + def get_validator_change(cls, bigchain, height=None): + """Return the latest change to the validator set + + :return: { + 'height': , + 'asset': { + 'height': , + 'validators': , + 'election_id': + } + } + """ + return bigchain.get_validator_change(height) + + @classmethod + def get_validators(cls, bigchain, height=None): + """Return a dictionary of validators with key as `public_key` and + value as the `voting_power` + """ + validators = {} + for validator in bigchain.get_validators(height): + # NOTE: we assume that Tendermint encodes public key in base64 + public_key = public_key_from_ed25519_key(key_from_base64(validator['pub_key']['data'])) + validators[public_key] = validator['voting_power'] + + return validators + + @classmethod + def recipients(cls, bigchain): + """Convert validator dictionary to a recipient list for `Transaction`""" + + recipients = [] + for public_key, voting_power in cls.get_validators(bigchain).items(): + recipients.append(([public_key], voting_power)) + + return recipients + + @classmethod + def is_same_topology(cls, current_topology, election_topology): + voters = {} + for voter in election_topology: + if len(voter.public_keys) > 1: + return False + + [public_key] = voter.public_keys + voting_power = voter.amount + voters[public_key] = voting_power + + # Check whether the voters and their votes is same to that of the + # validators and their voting power in the network + return current_topology == voters + + def validate(self, bigchain, current_transactions=[]): + """Validate election transaction + + NOTE: + * A valid election is initiated by an existing validator. + + * A valid election is one where voters are validators and votes are + allocated according to the voting power of each validator node. + + Args: + :param bigchain: (BigchainDB) an instantiated bigchaindb.lib.BigchainDB object. + :param current_transactions: (list) A list of transactions to be validated along with the election + + Returns: + ValidatorElection object + + Raises: + ValidationError: If the election is invalid + """ + input_conditions = [] + + duplicates = any(txn for txn in current_transactions if txn.id == self.id) + if bigchain.get_transaction(self.id) or duplicates: + raise DuplicateTransaction('transaction `{}` already exists' + .format(self.id)) + + if not self.inputs_valid(input_conditions): + raise InvalidSignature('Transaction signature is invalid.') + + current_validators = self.get_validators(bigchain) + + # NOTE: Proposer should be a single node + if len(self.inputs) != 1 or len(self.inputs[0].owners_before) != 1: + raise MultipleInputsError('`tx_signers` must be a list instance of length one') + + # NOTE: Check if the proposer is a validator. + [election_initiator_node_pub_key] = self.inputs[0].owners_before + if election_initiator_node_pub_key not in current_validators.keys(): + raise InvalidProposer('Public key is not a part of the validator set') + + # NOTE: Check if all validators have been assigned votes equal to their voting power + if not self.is_same_topology(current_validators, self.outputs): + raise UnequalValidatorSet('Validator set much be exactly same to the outputs of election') + + return self + + @classmethod + def generate(cls, initiator, voters, election_data, metadata=None): + (inputs, outputs) = cls.validate_create(initiator, voters, election_data, metadata) + election = cls(cls.ELECTION_TYPE, {'data': election_data}, inputs, outputs, metadata) + cls.validate_schema(election.to_dict(), skip_id=True) + return election + + @classmethod + def validate_schema(cls, tx, skip_id=False): + """Validate the election transaction. Since `ELECTION` extends `CREATE` transaction, all the validations for + `CREATE` transaction should be inherited + """ + if not skip_id: + cls.validate_id(tx) + _validate_schema(TX_SCHEMA_COMMON, tx) + _validate_schema(TX_SCHEMA_CREATE, tx) + + @classmethod + def create(cls, tx_signers, recipients, metadata=None, asset=None): + raise NotImplementedError + + @classmethod + def transfer(cls, tx_signers, recipients, metadata=None, asset=None): + raise NotImplementedError + + @classmethod + def to_public_key(cls, election_id): + return base58.b58encode(bytes.fromhex(election_id)) + + @classmethod + def count_votes(cls, election_pk, transactions, getter=getattr): + votes = 0 + for txn in transactions: + if getter(txn, 'operation') == 'VALIDATOR_ELECTION_VOTE': + for output in getter(txn, 'outputs'): + # NOTE: We enforce that a valid vote to election id will have only + # election_pk in the output public keys, including any other public key + # along with election_pk will lead to vote being not considered valid. + if len(getter(output, 'public_keys')) == 1 and [election_pk] == getter(output, 'public_keys'): + votes = votes + int(getter(output, 'amount')) + return votes + + def get_commited_votes(self, bigchain, election_pk=None): + if election_pk is None: + election_pk = self.to_public_key(self.id) + txns = list(backend.query.get_asset_tokens_for_public_key(bigchain.connection, + self.id, + election_pk)) + return self.count_votes(election_pk, txns, dict.get) + + @classmethod + def has_concluded(cls, bigchain, election_id, current_votes=[], height=None): + """Check if the given `election_id` can be concluded or not + NOTE: + * Election is concluded iff the current validator set is exactly equal + to the validator set encoded in election outputs + * Election can concluded only if the current votes achieves a supermajority + """ + election = bigchain.get_transaction(election_id) + + if election: + election_pk = election.to_public_key(election.id) + votes_committed = election.get_commited_votes(bigchain, election_pk) + votes_current = election.count_votes(election_pk, current_votes) + current_validators = election.get_validators(bigchain, height) + + if election.is_same_topology(current_validators, election.outputs): + total_votes = sum(current_validators.values()) + if (votes_committed < (2/3)*total_votes) and \ + (votes_committed + votes_current >= (2/3)*total_votes): + return election + return False + + def get_status(self, bigchain): + concluded = self.get_election_result(self.id, bigchain) + if concluded: + return self.CONCLUDED + + latest_change = self.get_validator_change(bigchain) + latest_change_height = latest_change['height'] + election_height = bigchain.get_block_containing_tx(self.id)[0] + + if latest_change_height >= election_height: + return self.INCONCLUSIVE + else: + return self.ONGOING + + def get_election_result(self, election_id, bigchain): + result = bigchain.get_result_by_election_id(election_id, self.DB_TABLE) + return result + + @classmethod + def is_approved(cls, bigchain, new_height, txns): + votes = {} + for txn in txns: + if not isinstance(txn, cls.VOTE_TYPE): + continue + + election_id = txn.asset['id'] + election_votes = votes.get(election_id, []) + election_votes.append(txn) + votes[election_id] = election_votes + + election = cls.has_concluded(bigchain, election_id, election_votes, new_height) + # Once an election concludes any other conclusion for the same + # or any other election is invalidated + if election: + return cls.on_approval(bigchain, election, new_height) + return [] + + @classmethod + def on_approval(cls, bigchain, election, new_height): + raise NotImplementedError diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 621960fa..b9ce4816 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -142,9 +142,9 @@ class App(BaseApplication): # Check if the current block concluded any validator elections and # update the locally tracked validator set - validator_updates = ValidatorElection.get_validator_update(self.bigchaindb, - self.new_height, - self.block_transactions) + validator_updates = ValidatorElection.is_approved(self.bigchaindb, + self.new_height, + self.block_transactions) # Store pre-commit state to recover in case there is a crash # during `commit` diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index 05ca3e69..5cc5ff0f 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -429,13 +429,10 @@ class BigchainDB(object): validators = result['validators'] return validators - def get_validators_by_election_id(self, election_id): - result = backend.query.get_validator_set_by_election_id(self.connection, election_id) + def get_result_by_election_id(self, election_id, table): + result = backend.query.get_result_by_election_id(self.connection, election_id, table) return result - def delete_validator_update(self): - return backend.query.delete_validator_update(self.connection) - def store_pre_commit_state(self, state): return backend.query.store_pre_commit_state(self.connection, state) diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 7d9a6fbc..3cc4fc26 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -2,263 +2,56 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -import base58 - -from bigchaindb import backend -from bigchaindb.common.exceptions import (InvalidSignature, - MultipleInputsError, - InvalidProposer, - UnequalValidatorSet, - InvalidPowerChange, - DuplicateTransaction) -from bigchaindb.tendermint_utils import key_from_base64 -from bigchaindb.common.crypto import (public_key_from_ed25519_key) -from bigchaindb.common.transaction import Transaction +from bigchaindb.common.exceptions import InvalidPowerChange +from bigchaindb.common.election import Election from bigchaindb.common.schema import (_validate_schema, - TX_SCHEMA_VALIDATOR_ELECTION, - TX_SCHEMA_COMMON, - TX_SCHEMA_CREATE) + TX_SCHEMA_VALIDATOR_ELECTION) from . import ValidatorElectionVote from .validator_utils import (new_validator_set, encode_validator) -class ValidatorElection(Transaction): +class ValidatorElection(Election): - VALIDATOR_ELECTION = 'VALIDATOR_ELECTION' + ELECTION_TYPE = 'VALIDATOR_ELECTION' # NOTE: this transaction class extends create so the operation inheritence is achieved # by renaming CREATE to VALIDATOR_ELECTION - CREATE = VALIDATOR_ELECTION - ALLOWED_OPERATIONS = (VALIDATOR_ELECTION,) - # Election Statuses: - ONGOING = 'ongoing' - CONCLUDED = 'concluded' - INCONCLUSIVE = 'inconclusive' - ELECTION_THRESHOLD = 2 / 3 - - def __init__(self, operation, asset, inputs, outputs, - metadata=None, version=None, hash_id=None): - # operation `CREATE` is being passed as argument as `VALIDATOR_ELECTION` is an extension - # of `CREATE` and any validation on `CREATE` in the parent class should apply to it - super().__init__(operation, asset, inputs, outputs, metadata, version, hash_id) - - @classmethod - def get_validator_change(cls, bigchain, height=None): - """Return the latest change to the validator set - - :return: { - 'height': , - 'asset': { - 'height': , - 'validators': , - 'election_id': - } - } - """ - return bigchain.get_validator_change(height) - - @classmethod - def get_validators(cls, bigchain, height=None): - """Return a dictionary of validators with key as `public_key` and - value as the `voting_power` - """ - validators = {} - for validator in bigchain.get_validators(height): - # NOTE: we assume that Tendermint encodes public key in base64 - public_key = public_key_from_ed25519_key(key_from_base64(validator['pub_key']['data'])) - validators[public_key] = validator['voting_power'] - - return validators - - @classmethod - def recipients(cls, bigchain): - """Convert validator dictionary to a recipient list for `Transaction`""" - - recipients = [] - for public_key, voting_power in cls.get_validators(bigchain).items(): - recipients.append(([public_key], voting_power)) - - return recipients - - @classmethod - def is_same_topology(cls, current_topology, election_topology): - voters = {} - for voter in election_topology: - if len(voter.public_keys) > 1: - return False - - [public_key] = voter.public_keys - voting_power = voter.amount - voters[public_key] = voting_power - - # Check whether the voters and their votes is same to that of the - # validators and their voting power in the network - return (current_topology == voters) + CREATE = ELECTION_TYPE + ALLOWED_OPERATIONS = (ELECTION_TYPE,) + DB_TABLE = 'validators' + VOTE_TYPE = ValidatorElectionVote def validate(self, bigchain, current_transactions=[]): - """Validate election transaction - For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21 - - NOTE: - * A valid election is initiated by an existing validator. - - * A valid election is one where voters are validators and votes are - alloacted according to the voting power of each validator node. - - Args: - bigchain (BigchainDB): an instantiated bigchaindb.lib.BigchainDB object. - - Returns: - ValidatorElection object - - Raises: - ValidationError: If the election is invalid + """For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21 """ - input_conditions = [] - - duplicates = any(txn for txn in current_transactions if txn.id == self.id) - if bigchain.get_transaction(self.id) or duplicates: - raise DuplicateTransaction('transaction `{}` already exists' - .format(self.id)) - - if not self.inputs_valid(input_conditions): - raise InvalidSignature('Transaction signature is invalid.') current_validators = self.get_validators(bigchain) - # NOTE: Proposer should be a single node - if len(self.inputs) != 1 or len(self.inputs[0].owners_before) != 1: - raise MultipleInputsError('`tx_signers` must be a list instance of length one') + super(ValidatorElection, self).validate(bigchain, current_transactions=current_transactions) # NOTE: change more than 1/3 of the current power is not allowed if self.asset['data']['power'] >= (1/3)*sum(current_validators.values()): raise InvalidPowerChange('`power` change must be less than 1/3 of total power') - # NOTE: Check if the proposer is a validator. - [election_initiator_node_pub_key] = self.inputs[0].owners_before - if election_initiator_node_pub_key not in current_validators.keys(): - raise InvalidProposer('Public key is not a part of the validator set') - - # NOTE: Check if all validators have been assigned votes equal to their voting power - if not self.is_same_topology(current_validators, self.outputs): - raise UnequalValidatorSet('Validator set much be exactly same to the outputs of election') - return self - @classmethod - def generate(cls, initiator, voters, election_data, metadata=None): - (inputs, outputs) = cls.validate_create(initiator, voters, election_data, metadata) - election = cls(cls.VALIDATOR_ELECTION, {'data': election_data}, inputs, outputs, metadata) - cls.validate_schema(election.to_dict(), skip_id=True) - return election - @classmethod def validate_schema(cls, tx, skip_id=False): - """Validate the validator election transaction. Since `VALIDATOR_ELECTION` extends `CREATE` - transaction, all the validations for `CREATE` transaction should be inherited + """Validate the validator election transaction. Since `VALIDATOR_ELECTION` extends `ELECTION` + transaction, all the validations for `ELECTION` transaction are covered by `super` """ - if not skip_id: - cls.validate_id(tx) - _validate_schema(TX_SCHEMA_COMMON, tx) - _validate_schema(TX_SCHEMA_CREATE, tx) + + super(ValidatorElection, cls).validate_schema(tx, skip_id=skip_id) + _validate_schema(TX_SCHEMA_VALIDATOR_ELECTION, tx) @classmethod - def create(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + def on_approval(cls, bigchain, election, new_height): + # The new validator set comes into effect from height = new_height+1 + validator_updates = [election.asset['data']] + curr_validator_set = bigchain.get_validators(new_height) + updated_validator_set = new_validator_set(curr_validator_set, + validator_updates) - @classmethod - def transfer(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError - - @classmethod - def to_public_key(cls, election_id): - return base58.b58encode(bytes.fromhex(election_id)) - - @classmethod - def count_votes(cls, election_pk, transactions, getter=getattr): - votes = 0 - for txn in transactions: - if getter(txn, 'operation') == 'VALIDATOR_ELECTION_VOTE': - for output in getter(txn, 'outputs'): - # NOTE: We enforce that a valid vote to election id will have only - # election_pk in the output public keys, including any other public key - # along with election_pk will lead to vote being not considered valid. - if len(getter(output, 'public_keys')) == 1 and [election_pk] == getter(output, 'public_keys'): - votes = votes + int(getter(output, 'amount')) - return votes - - def get_commited_votes(self, bigchain, election_pk=None): - if election_pk is None: - election_pk = self.to_public_key(self.id) - txns = list(backend.query.get_asset_tokens_for_public_key(bigchain.connection, - self.id, - election_pk)) - return self.count_votes(election_pk, txns, dict.get) - - @classmethod - def has_concluded(cls, bigchain, election_id, current_votes=[], height=None): - """Check if the given `election_id` can be concluded or not - NOTE: - * Election is concluded iff the current validator set is exactly equal - to the validator set encoded in election outputs - * Election can concluded only if the current votes achieves a supermajority - """ - election = bigchain.get_transaction(election_id) - - if election: - election_pk = election.to_public_key(election.id) - votes_commited = election.get_commited_votes(bigchain, election_pk) - votes_current = election.count_votes(election_pk, current_votes) - current_validators = election.get_validators(bigchain, height) - - if election.is_same_topology(current_validators, election.outputs): - total_votes = sum(current_validators.values()) - if (votes_commited < (2/3)*total_votes) and \ - (votes_commited + votes_current >= (2/3)*total_votes): - return election - return False - - @classmethod - def get_validator_update(cls, bigchain, new_height, txns): - votes = {} - for txn in txns: - if not isinstance(txn, ValidatorElectionVote): - continue - - election_id = txn.asset['id'] - election_votes = votes.get(election_id, []) - election_votes.append(txn) - votes[election_id] = election_votes - - election = cls.has_concluded(bigchain, election_id, election_votes, new_height) - # Once an election concludes any other conclusion for the same - # or any other election is invalidated - if election: - # The new validator set comes into effect from height = new_height+1 - validator_updates = [election.asset['data']] - curr_validator_set = bigchain.get_validators(new_height) - updated_validator_set = new_validator_set(curr_validator_set, - validator_updates) - - updated_validator_set = [v for v in updated_validator_set if v['voting_power'] > 0] - bigchain.store_validator_set(new_height+1, updated_validator_set, election.id) - return [encode_validator(election.asset['data'])] - return [] - - def get_validator_update_by_election_id(self, election_id, bigchain): - result = bigchain.get_validators_by_election_id(election_id) - return result - - def get_status(self, bigchain): - concluded = self.get_validator_update_by_election_id(self.id, bigchain) - if concluded: - return self.CONCLUDED - - latest_change = self.get_validator_change(bigchain) - latest_change_height = latest_change['height'] - election_height = bigchain.get_block_containing_tx(self.id)[0] - - if latest_change_height >= election_height: - return self.INCONCLUSIVE - else: - return self.ONGOING + updated_validator_set = [v for v in updated_validator_set if v['voting_power'] > 0] + bigchain.store_validator_set(new_height+1, updated_validator_set, election.id) + return [encode_validator(election.asset['data'])] diff --git a/setup.py b/setup.py index dcecca51..2e7979d1 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,7 @@ install_requires = [ 'pyyaml~=3.12', 'aiohttp~=3.0', 'bigchaindb-abci==0.5.1', - 'setproctitle~=1.1.0', + 'setproctitle~=1.1.0', 'base58' ] setup( diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 40958aa2..98f3a9b2 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -189,7 +189,7 @@ def test_end_block_return_validator_updates(b, init_chain_request): resp = app.end_block(RequestEndBlock(height=99)) assert resp.validator_updates[0] == encode_validator(validator) - updates = b.get_validator_update() + updates = b.is_approved() assert updates == [] diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 4e8ff6b3..ea4b1699 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -163,11 +163,11 @@ def test_validator_updates(b, validator_pub_key): 'update_id': VALIDATOR_UPDATE_ID} query.store_validator_update(b.connection, validator_update) - updates = b.get_validator_update() + updates = b.is_approved() assert updates == [validator_update['validator']] b.delete_validator_update() - assert b.get_validator_update() == [] + assert b.is_approved() == [] @pytest.mark.bdb diff --git a/tests/upsert_validator/test_validator_election_vote.py b/tests/upsert_validator/test_validator_election_vote.py index 6c92af99..a9303675 100644 --- a/tests/upsert_validator/test_validator_election_vote.py +++ b/tests/upsert_validator/test_validator_election_vote.py @@ -299,17 +299,17 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): assert not ValidatorElection.has_concluded(b, election.id, [tx_vote0, tx_vote1]) assert ValidatorElection.has_concluded(b, election.id, [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 ValidatorElection.is_approved(b, 4, [tx_vote0]) == [] + assert ValidatorElection.is_approved(b, 4, [tx_vote0, tx_vote1]) == [] - update = ValidatorElection.get_validator_update(b, 4, [tx_vote0, tx_vote1, tx_vote2]) + update = ValidatorElection.is_approved(b, 4, [tx_vote0, tx_vote1, tx_vote2]) 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]) + update = ValidatorElection.is_approved(b, 4, [tx_vote2]) update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') assert len(update) == 1 assert update_public_key == public_key64 @@ -332,7 +332,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): b.store_bulk_transactions([tx_vote0, tx_vote1]) - update = ValidatorElection.get_validator_update(b, 9, [tx_vote2]) + update = ValidatorElection.is_approved(b, 9, [tx_vote2]) update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') assert len(update) == 1 assert update_public_key == public_key64 From 4a631ef3aefd2d822e7a9255125e9aadeae5e9ee Mon Sep 17 00:00:00 2001 From: z-bowen Date: Fri, 31 Aug 2018 14:07:49 +0200 Subject: [PATCH 02/13] Problem: Adding base58 as a requirement seems to break the build... Solution: Reverting the changes --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2e7979d1..dcecca51 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,7 @@ install_requires = [ 'pyyaml~=3.12', 'aiohttp~=3.0', 'bigchaindb-abci==0.5.1', - 'setproctitle~=1.1.0', 'base58' + 'setproctitle~=1.1.0', ] setup( From 560a8154b78f5fb9e81761eb2d38b9766d7ad30f Mon Sep 17 00:00:00 2001 From: z-bowen Date: Mon, 3 Sep 2018 12:00:06 +0200 Subject: [PATCH 03/13] Problem: Responding to a suggestion for improved method naming Solution: Refactored `get_result_by_election_id` to `get_election_result_by_id` --- bigchaindb/backend/localmongodb/query.py | 2 +- bigchaindb/backend/query.py | 2 +- bigchaindb/common/election.py | 2 +- bigchaindb/lib.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 4e4557c8..aa80909e 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -300,7 +300,7 @@ def get_validator_set(conn, height=None): @register_query(LocalMongoDBConnection) -def get_result_by_election_id(conn, election_id, table): +def get_election_result_by_id(conn, election_id, table): query = {'election_id': election_id} cursor = conn.run( diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 86028a05..54ff8900 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -361,7 +361,7 @@ def get_validator_set(conn, height): @singledispatch -def get_result_by_election_id(conn, election_id, table): +def get_election_result_by_id(conn, election_id, table): """Return a validator set change with the specified election_id """ diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index e114a6c6..7c07fe8b 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -221,7 +221,7 @@ class Election(Transaction): return self.ONGOING def get_election_result(self, election_id, bigchain): - result = bigchain.get_result_by_election_id(election_id, self.DB_TABLE) + result = bigchain.get_election_result_by_id(election_id, self.DB_TABLE) return result @classmethod diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index 5cc5ff0f..bee2f123 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -430,7 +430,7 @@ class BigchainDB(object): return validators def get_result_by_election_id(self, election_id, table): - result = backend.query.get_result_by_election_id(self.connection, election_id, table) + result = backend.query.get_election_result_by_id(self.connection, election_id, table) return result def store_pre_commit_state(self, state): From db45374d3c690429d18a25bcc319f8056c016500 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Mon, 3 Sep 2018 12:45:37 +0200 Subject: [PATCH 04/13] Problem: No need to store different types of elections in their own tables Solution: Remove `DB_TABLE` property from `Election` class --- bigchaindb/backend/localmongodb/query.py | 4 ++-- bigchaindb/backend/query.py | 2 +- bigchaindb/common/election.py | 4 +--- bigchaindb/lib.py | 4 ++-- bigchaindb/upsert_validator/validator_election.py | 1 - 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index aa80909e..992eaf8a 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -300,11 +300,11 @@ def get_validator_set(conn, height=None): @register_query(LocalMongoDBConnection) -def get_election_result_by_id(conn, election_id, table): +def get_election_result_by_id(conn, election_id): query = {'election_id': election_id} cursor = conn.run( - conn.collection(table) + conn.collection('validators') .find(query, projection={'_id': False}) ) diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 54ff8900..3bf46c84 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -361,7 +361,7 @@ def get_validator_set(conn, height): @singledispatch -def get_election_result_by_id(conn, election_id, table): +def get_election_result_by_id(conn, election_id): """Return a validator set change with the specified election_id """ diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index 7c07fe8b..6388019b 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -23,8 +23,6 @@ class Election(Transaction): # NOTE: this transaction class extends create so the operation inheritance is achieved # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) ELECTION_TYPE = None - # the name of the mongodb table managed by the election - DB_TABLE = None # the model for votes issued by the election VOTE_TYPE = None # Election Statuses: @@ -221,7 +219,7 @@ class Election(Transaction): return self.ONGOING def get_election_result(self, election_id, bigchain): - result = bigchain.get_election_result_by_id(election_id, self.DB_TABLE) + result = bigchain.get_election_result_by_id(election_id) return result @classmethod diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index bee2f123..f50b0300 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -429,8 +429,8 @@ class BigchainDB(object): validators = result['validators'] return validators - def get_result_by_election_id(self, election_id, table): - result = backend.query.get_election_result_by_id(self.connection, election_id, table) + def get_election_result_by_id(self, election_id): + result = backend.query.get_election_result_by_id(self.connection, election_id) return result def store_pre_commit_state(self, state): diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 3cc4fc26..998ca028 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -17,7 +17,6 @@ class ValidatorElection(Election): # by renaming CREATE to VALIDATOR_ELECTION CREATE = ELECTION_TYPE ALLOWED_OPERATIONS = (ELECTION_TYPE,) - DB_TABLE = 'validators' VOTE_TYPE = ValidatorElectionVote def validate(self, bigchain, current_transactions=[]): From bd76b31e40f826e76feaeb17d956090efa33e902 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 10:55:23 +0200 Subject: [PATCH 05/13] Revert "Problem: No need to store different types of elections in their own tables" This reverts commit db45374d3c690429d18a25bcc319f8056c016500. --- bigchaindb/backend/localmongodb/query.py | 4 ++-- bigchaindb/backend/query.py | 2 +- bigchaindb/common/election.py | 4 +++- bigchaindb/lib.py | 4 ++-- bigchaindb/upsert_validator/validator_election.py | 1 + 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 992eaf8a..aa80909e 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -300,11 +300,11 @@ def get_validator_set(conn, height=None): @register_query(LocalMongoDBConnection) -def get_election_result_by_id(conn, election_id): +def get_election_result_by_id(conn, election_id, table): query = {'election_id': election_id} cursor = conn.run( - conn.collection('validators') + conn.collection(table) .find(query, projection={'_id': False}) ) diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 3bf46c84..54ff8900 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -361,7 +361,7 @@ def get_validator_set(conn, height): @singledispatch -def get_election_result_by_id(conn, election_id): +def get_election_result_by_id(conn, election_id, table): """Return a validator set change with the specified election_id """ diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index 6388019b..7c07fe8b 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -23,6 +23,8 @@ class Election(Transaction): # NOTE: this transaction class extends create so the operation inheritance is achieved # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) ELECTION_TYPE = None + # the name of the mongodb table managed by the election + DB_TABLE = None # the model for votes issued by the election VOTE_TYPE = None # Election Statuses: @@ -219,7 +221,7 @@ class Election(Transaction): return self.ONGOING def get_election_result(self, election_id, bigchain): - result = bigchain.get_election_result_by_id(election_id) + result = bigchain.get_election_result_by_id(election_id, self.DB_TABLE) return result @classmethod diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index f50b0300..bee2f123 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -429,8 +429,8 @@ class BigchainDB(object): validators = result['validators'] return validators - def get_election_result_by_id(self, election_id): - result = backend.query.get_election_result_by_id(self.connection, election_id) + def get_result_by_election_id(self, election_id, table): + result = backend.query.get_election_result_by_id(self.connection, election_id, table) return result def store_pre_commit_state(self, state): diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 998ca028..3cc4fc26 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -17,6 +17,7 @@ class ValidatorElection(Election): # by renaming CREATE to VALIDATOR_ELECTION CREATE = ELECTION_TYPE ALLOWED_OPERATIONS = (ELECTION_TYPE,) + DB_TABLE = 'validators' VOTE_TYPE = ValidatorElectionVote def validate(self, bigchain, current_transactions=[]): From b468504bfc6686d9211f642267076d03ba981419 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 11:12:51 +0200 Subject: [PATCH 06/13] Problem: Missed a method in `Bigchain` class when updating the naming for an election method Solution: Finished the refactoring --- bigchaindb/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index bee2f123..a1fb4129 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -429,7 +429,7 @@ class BigchainDB(object): validators = result['validators'] return validators - def get_result_by_election_id(self, election_id, table): + def get_election_result_by_id(self, election_id, table): result = backend.query.get_election_result_by_id(self.connection, election_id, table) return result From e7dae7db72f906a17dc37d362b83928bc91d4013 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 12:08:16 +0200 Subject: [PATCH 07/13] Problem: Need a table to store data for all elections Solution: Created the `elections` table with secondary_index `election_id` --- bigchaindb/backend/localmongodb/schema.py | 12 +++++++++--- bigchaindb/backend/schema.py | 2 +- tests/backend/localmongodb/test_schema.py | 13 ++++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/bigchaindb/backend/localmongodb/schema.py b/bigchaindb/backend/localmongodb/schema.py index 1ad88928..9bb3fbad 100644 --- a/bigchaindb/backend/localmongodb/schema.py +++ b/bigchaindb/backend/localmongodb/schema.py @@ -47,6 +47,7 @@ def create_indexes(conn, dbname): create_utxos_secondary_index(conn, dbname) create_pre_commit_secondary_index(conn, dbname) create_validators_secondary_index(conn, dbname) + create_elections_secondary_index(conn, dbname) @register_schema(LocalMongoDBConnection) @@ -133,6 +134,11 @@ def create_validators_secondary_index(conn, dbname): conn.conn[dbname]['validators'].create_index('height', name='height', unique=True,) - conn.conn[dbname]['validators'].create_index('election_id', - name='election_id', - unique=True,) + + +def create_elections_secondary_index(conn, dbname): + logger.info('Create `elections` secondary index.') + + conn.conn[dbname]['elections'].create_index('election_id', + name='election_id', + unique=True,) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index 04c1bdd0..1daacbbd 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) # Tables/collections that every backend database must create TABLES = ('transactions', 'blocks', 'assets', 'metadata', - 'validators', 'pre_commit', 'utxos') + 'validators', 'elections', 'pre_commit', 'utxos') VALID_LANGUAGES = ('danish', 'dutch', 'english', 'finnish', 'french', 'german', 'hungarian', 'italian', 'norwegian', 'portuguese', 'romanian', diff --git a/tests/backend/localmongodb/test_schema.py b/tests/backend/localmongodb/test_schema.py index 2481cd60..6996a127 100644 --- a/tests/backend/localmongodb/test_schema.py +++ b/tests/backend/localmongodb/test_schema.py @@ -24,7 +24,7 @@ def test_init_creates_db_tables_and_indexes(): collection_names = conn.conn[dbname].collection_names() assert set(collection_names) == { 'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'pre_commit', - 'validators' + 'validators', 'elections' } indexes = conn.conn[dbname]['assets'].index_information().keys() @@ -44,7 +44,10 @@ def test_init_creates_db_tables_and_indexes(): assert set(indexes) == {'_id_', 'pre_commit_id'} indexes = conn.conn[dbname]['validators'].index_information().keys() - assert set(indexes) == {'_id_', 'height', 'election_id'} + assert set(indexes) == {'_id_', 'height'} + + indexes = conn.conn[dbname]['elections'].index_information().keys() + assert set(indexes) == {'_id_', 'election_id'} def test_init_database_fails_if_db_exists(): @@ -78,7 +81,7 @@ def test_create_tables(): collection_names = conn.conn[dbname].collection_names() assert set(collection_names) == { - 'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'validators', + 'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'validators', 'elections', 'pre_commit'} @@ -116,6 +119,10 @@ def test_create_secondary_indexes(): assert index_info['utxo']['key'] == [('transaction_id', 1), ('output_index', 1)] + indexes = conn.conn[dbname]['elections'].index_information() + assert set(indexes.keys()) == {'_id_', 'election_id'} + assert indexes['election_id']['unique'] + indexes = conn.conn[dbname]['pre_commit'].index_information() assert set(indexes.keys()) == {'_id_', 'pre_commit_id'} assert indexes['pre_commit_id']['unique'] From 84a7cf7657feb4328bdad47a01350e4467dc2f1c Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 15:58:35 +0200 Subject: [PATCH 08/13] Problem: `Election` class needs to be updated to store concluded elections in the `elections` table Solution: Updated the class to use the new table --- bigchaindb/backend/localmongodb/query.py | 16 ++++++++++++++-- bigchaindb/backend/query.py | 9 ++++++++- bigchaindb/common/election.py | 15 +++++++++------ bigchaindb/lib.py | 12 ++++++++++-- tests/upsert_validator/conftest.py | 8 +++----- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 48e980d0..6fc5ba80 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -283,6 +283,18 @@ def store_validator_set(conn, validators_update): ) +@register_query(LocalMongoDBConnection) +def store_election(conn, election): + height = election['height'] + return conn.run( + conn.collection('elections').replace_one( + {'height': height}, + election, + upsert=True + ) + ) + + @register_query(LocalMongoDBConnection) def get_validator_set(conn, height=None): query = {} @@ -300,11 +312,11 @@ def get_validator_set(conn, height=None): @register_query(LocalMongoDBConnection) -def get_election_result_by_id(conn, election_id, table): +def get_election(conn, election_id): query = {'election_id': election_id} cursor = conn.run( - conn.collection(table) + conn.collection('elections') .find(query, projection={'_id': False}) ) diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 89995eff..30daf009 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -351,6 +351,13 @@ def store_validator_set(conn, validator_update): raise NotImplementedError +@singledispatch +def store_election(conn, validator_update): + """Store election results""" + + raise NotImplementedError + + @singledispatch def get_validator_set(conn, height): """Get validator set for a given `height`, if `height` is not specified @@ -361,7 +368,7 @@ def get_validator_set(conn, height): @singledispatch -def get_election_result_by_id(conn, election_id, table): +def get_election(conn, election_id): """Return a validator set change with the specified election_id """ diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index 7c07fe8b..f4a81ec3 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -23,8 +23,6 @@ class Election(Transaction): # NOTE: this transaction class extends create so the operation inheritance is achieved # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) ELECTION_TYPE = None - # the name of the mongodb table managed by the election - DB_TABLE = None # the model for votes issued by the election VOTE_TYPE = None # Election Statuses: @@ -160,7 +158,7 @@ class Election(Transaction): @classmethod def to_public_key(cls, election_id): - return base58.b58encode(bytes.fromhex(election_id)) + return base58.b58encode(bytes.fromhex(election_id)).decode() @classmethod def count_votes(cls, election_pk, transactions, getter=getattr): @@ -207,7 +205,7 @@ class Election(Transaction): return False def get_status(self, bigchain): - concluded = self.get_election_result(self.id, bigchain) + concluded = self.get_election(self.id, bigchain) if concluded: return self.CONCLUDED @@ -220,10 +218,14 @@ class Election(Transaction): else: return self.ONGOING - def get_election_result(self, election_id, bigchain): - result = bigchain.get_election_result_by_id(election_id, self.DB_TABLE) + def get_election(self, election_id, bigchain): + result = bigchain.get_election(election_id) return result + @classmethod + def store_election(cls, bigchain, election, height): + bigchain.store_election(height, election) + @classmethod def is_approved(cls, bigchain, new_height, txns): votes = {} @@ -240,6 +242,7 @@ class Election(Transaction): # Once an election concludes any other conclusion for the same # or any other election is invalidated if election: + cls.store_election(bigchain, election, new_height) return cls.on_approval(bigchain, election, new_height) return [] diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index 94268b12..f0f5a348 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -428,8 +428,8 @@ class BigchainDB(object): result = self.get_validator_change(height) return [] if result is None else result['validators'] - def get_election_result_by_id(self, election_id, table): - result = backend.query.get_election_result_by_id(self.connection, election_id, table) + def get_election(self, election_id): + result = backend.query.get_election(self.connection, election_id) return result def store_pre_commit_state(self, state): @@ -475,6 +475,14 @@ class BigchainDB(object): self.store_abci_chain(block['height'] + 1, new_chain_id, False) + def store_election(self, height, election): + """Store election results + :param height: the block height at which the election concluded + :param election: a concluded election + """ + return backend.query.store_election(self.connection, {'height': height, + 'election_id': election.id}) + Block = namedtuple('Block', ('app_hash', 'height', 'transactions')) diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index 20906ada..8bb472f4 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -62,12 +62,10 @@ def ongoing_election(b, valid_election, ed25519_node_keys): @pytest.fixture def concluded_election(b, ongoing_election, ed25519_node_keys): - validators = b.get_validators(height=1) - validator_update = {'validators': validators, - 'height': 2, - 'election_id': ongoing_election.id} + election_result = {'height': 2, + 'election_id': ongoing_election.id} - query.store_validator_set(b.connection, validator_update) + query.store_election(b.connection, election_result) return ongoing_election From 1e3caf8ccdc0913211ec8c7abbb93abbfb8a97d3 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 17:13:34 +0200 Subject: [PATCH 09/13] Problem: `UpsertValidatorVote` can be generalized to just be `Vote` Solution: Renamed, refactored and moved the `Vote` class to tie in with the more general `Election` base class --- bigchaindb/__init__.py | 4 +- bigchaindb/commands/bigchaindb.py | 9 +- bigchaindb/common/election.py | 5 +- .../common/schema/transaction_v2.0.yaml | 2 +- ...nsaction_validator_election_vote_v2.0.yaml | 4 +- .../vote.py} | 12 +-- bigchaindb/upsert_validator/__init__.py | 1 - .../upsert_validator/validator_election.py | 3 - tests/upsert_validator/conftest.py | 10 +-- ..._vote.py => test_upsert_validator_vote.py} | 83 ++++++++++--------- 10 files changed, 66 insertions(+), 67 deletions(-) rename bigchaindb/{upsert_validator/validator_election_vote.py => common/vote.py} (86%) rename tests/upsert_validator/{test_validator_election_vote.py => test_upsert_validator_vote.py} (79%) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index b936d8aa..b63afa3d 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -94,9 +94,9 @@ _config = copy.deepcopy(config) from bigchaindb.common.transaction import Transaction # noqa from bigchaindb import models # noqa from bigchaindb.upsert_validator import ValidatorElection # noqa -from bigchaindb.upsert_validator import ValidatorElectionVote # noqa +from bigchaindb.common.vote import Vote # noqa Transaction.register_type(Transaction.CREATE, models.Transaction) Transaction.register_type(Transaction.TRANSFER, models.Transaction) Transaction.register_type(ValidatorElection.ELECTION_TYPE, ValidatorElection) -Transaction.register_type(ValidatorElectionVote.VALIDATOR_ELECTION_VOTE, ValidatorElectionVote) +Transaction.register_type(Vote.VOTE, Vote) diff --git a/bigchaindb/commands/bigchaindb.py b/bigchaindb/commands/bigchaindb.py index 19cb0e2d..d4678ca2 100644 --- a/bigchaindb/commands/bigchaindb.py +++ b/bigchaindb/commands/bigchaindb.py @@ -17,9 +17,10 @@ from bigchaindb.utils import load_node_key from bigchaindb.common.exceptions import (DatabaseAlreadyExists, DatabaseDoesNotExist, ValidationError) +from bigchaindb.common.vote import Vote import bigchaindb from bigchaindb import (backend, ValidatorElection, - BigchainDB, ValidatorElectionVote) + BigchainDB) from bigchaindb.backend import schema from bigchaindb.backend import query from bigchaindb.backend.query import PRE_COMMIT_ID @@ -175,9 +176,9 @@ def run_upsert_validator_approve(args, bigchain): inputs = [i for i in tx.to_inputs() if key.public_key in i.owners_before] election_pub_key = ValidatorElection.to_public_key(tx.id) - approval = ValidatorElectionVote.generate(inputs, - [([election_pub_key], voting_power)], - tx.id).sign([key.private_key]) + approval = Vote.generate(inputs, + [([election_pub_key], voting_power)], + tx.id).sign([key.private_key]) approval.validate(bigchain) resp = bigchain.write_transaction(approval, 'broadcast_tx_commit') diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index f4a81ec3..ddc92495 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -5,6 +5,7 @@ import base58 from bigchaindb import backend +from bigchaindb.common.vote import Vote from bigchaindb.common.exceptions import (InvalidSignature, MultipleInputsError, InvalidProposer, @@ -24,7 +25,7 @@ class Election(Transaction): # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) ELECTION_TYPE = None # the model for votes issued by the election - VOTE_TYPE = None + VOTE_TYPE = Vote # Election Statuses: ONGOING = 'ongoing' CONCLUDED = 'concluded' @@ -164,7 +165,7 @@ class Election(Transaction): def count_votes(cls, election_pk, transactions, getter=getattr): votes = 0 for txn in transactions: - if getter(txn, 'operation') == 'VALIDATOR_ELECTION_VOTE': + if getter(txn, 'operation') == 'VOTE': for output in getter(txn, 'outputs'): # NOTE: We enforce that a valid vote to election id will have only # election_pk in the output public keys, including any other public key diff --git a/bigchaindb/common/schema/transaction_v2.0.yaml b/bigchaindb/common/schema/transaction_v2.0.yaml index acc8c6b5..562c0d86 100644 --- a/bigchaindb/common/schema/transaction_v2.0.yaml +++ b/bigchaindb/common/schema/transaction_v2.0.yaml @@ -63,7 +63,7 @@ definitions: - CREATE - TRANSFER - VALIDATOR_ELECTION - - VALIDATOR_ELECTION_VOTE + - VOTE asset: type: object additionalProperties: false diff --git a/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml b/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml index c17fb229..5e7c4763 100644 --- a/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml +++ b/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml @@ -5,14 +5,14 @@ --- "$schema": "http://json-schema.org/draft-04/schema#" type: object -title: Validator Election Vote Schema - Vote on a validator set change +title: Vote Schema - Vote on an election required: - operation - outputs properties: operation: type: string - value: "VALIDATOR_ELECTION_VOTE" + value: "VOTE" outputs: type: array items: diff --git a/bigchaindb/upsert_validator/validator_election_vote.py b/bigchaindb/common/vote.py similarity index 86% rename from bigchaindb/upsert_validator/validator_election_vote.py rename to bigchaindb/common/vote.py index 7620b289..7b6230ba 100644 --- a/bigchaindb/upsert_validator/validator_election_vote.py +++ b/bigchaindb/common/vote.py @@ -9,13 +9,13 @@ from bigchaindb.common.schema import (_validate_schema, TX_SCHEMA_VALIDATOR_ELECTION_VOTE) -class ValidatorElectionVote(Transaction): +class Vote(Transaction): - VALIDATOR_ELECTION_VOTE = 'VALIDATOR_ELECTION_VOTE' + VOTE = 'VOTE' # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is # overriden to re-use methods from parent class - TRANSFER = VALIDATOR_ELECTION_VOTE - ALLOWED_OPERATIONS = (VALIDATOR_ELECTION_VOTE,) + TRANSFER = VOTE + ALLOWED_OPERATIONS = (VOTE,) def validate(self, bigchain, current_transactions=[]): """Validate election vote transaction @@ -28,7 +28,7 @@ class ValidatorElectionVote(Transaction): bigchain (BigchainDB): an instantiated bigchaindb.lib.BigchainDB object. Returns: - ValidatorElectionVote object + Vote object Raises: ValidationError: If the election vote is invalid @@ -39,7 +39,7 @@ class ValidatorElectionVote(Transaction): @classmethod def generate(cls, inputs, recipients, election_id, metadata=None): (inputs, outputs) = cls.validate_transfer(inputs, recipients, election_id, metadata) - election_vote = cls(cls.VALIDATOR_ELECTION_VOTE, {'id': election_id}, inputs, outputs, metadata) + election_vote = cls(cls.VOTE, {'id': election_id}, inputs, outputs, metadata) cls.validate_schema(election_vote.to_dict(), skip_id=True) return election_vote diff --git a/bigchaindb/upsert_validator/__init__.py b/bigchaindb/upsert_validator/__init__.py index 90a02a0b..0aa49f35 100644 --- a/bigchaindb/upsert_validator/__init__.py +++ b/bigchaindb/upsert_validator/__init__.py @@ -3,5 +3,4 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 -from bigchaindb.upsert_validator.validator_election_vote import ValidatorElectionVote # noqa from bigchaindb.upsert_validator.validator_election import ValidatorElection # noqa diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 3cc4fc26..0b94c71e 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -6,7 +6,6 @@ from bigchaindb.common.exceptions import InvalidPowerChange from bigchaindb.common.election import Election from bigchaindb.common.schema import (_validate_schema, TX_SCHEMA_VALIDATOR_ELECTION) -from . import ValidatorElectionVote from .validator_utils import (new_validator_set, encode_validator) @@ -17,8 +16,6 @@ class ValidatorElection(Election): # by renaming CREATE to VALIDATOR_ELECTION CREATE = ELECTION_TYPE ALLOWED_OPERATIONS = (ELECTION_TYPE,) - DB_TABLE = 'validators' - VOTE_TYPE = ValidatorElectionVote def validate(self, bigchain, current_transactions=[]): """For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21 diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index 8bb472f4..30f1f300 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -4,7 +4,7 @@ import pytest -from bigchaindb import ValidatorElectionVote +from bigchaindb import Vote from bigchaindb.backend.localmongodb import query from bigchaindb.lib import Block from bigchaindb.upsert_validator import ValidatorElection @@ -89,9 +89,9 @@ def vote(election, voter, keys, b): election_pub_key = ValidatorElection.to_public_key(election.id) - v = ValidatorElectionVote.generate([election_input], - [([election_pub_key], votes)], - election_id=election.id)\ - .sign([key.private_key]) + v = Vote.generate([election_input], + [([election_pub_key], votes)], + election_id=election.id)\ + .sign([key.private_key]) b.store_bulk_transactions([v]) return v diff --git a/tests/upsert_validator/test_validator_election_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py similarity index 79% rename from tests/upsert_validator/test_validator_election_vote.py rename to tests/upsert_validator/test_upsert_validator_vote.py index a9303675..6cea8ac6 100644 --- a/tests/upsert_validator/test_validator_election_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -6,10 +6,11 @@ import pytest import codecs from bigchaindb.tendermint_utils import public_key_to_base64 -from bigchaindb.upsert_validator import ValidatorElection, ValidatorElectionVote +from bigchaindb.upsert_validator import ValidatorElection from bigchaindb.common.exceptions import AmountError from bigchaindb.common.crypto import generate_key_pair from bigchaindb.common.exceptions import ValidationError +from bigchaindb.common.vote import Vote from tests.utils import generate_block pytestmark = [pytest.mark.execute] @@ -27,10 +28,10 @@ def test_upsert_validator_valid_election_vote(b_mock, valid_election, ed25519_no election_pub_key = ValidatorElection.to_public_key(valid_election.id) - vote = ValidatorElectionVote.generate([input0], - [([election_pub_key], votes)], - election_id=valid_election.id)\ - .sign([key0.private_key]) + vote = Vote.generate([input0], + [([election_pub_key], votes)], + election_id=valid_election.id)\ + .sign([key0.private_key]) assert vote.validate(b_mock) @@ -48,10 +49,10 @@ def test_upsert_validator_valid_non_election_vote(b_mock, valid_election, ed2551 # Ensure that threshold conditions are now allowed with pytest.raises(ValidationError): - ValidatorElectionVote.generate([input0], - [([election_pub_key, key0.public_key], votes)], - election_id=valid_election.id)\ - .sign([key0.private_key]) + Vote.generate([input0], + [([election_pub_key, key0.public_key], votes)], + election_id=valid_election.id)\ + .sign([key0.private_key]) @pytest.mark.tendermint @@ -66,10 +67,10 @@ def test_upsert_validator_delegate_election_vote(b_mock, valid_election, ed25519 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]) + delegate_vote = Vote.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) @@ -77,17 +78,17 @@ def test_upsert_validator_delegate_election_vote(b_mock, valid_election, ed25519 election_pub_key = ValidatorElection.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]) + alice_casted_vote = Vote.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]) + key0_casted_vote = Vote.generate([key0_votes], + [([election_pub_key], votes-3)], + election_id=valid_election.id)\ + .sign([key0.private_key]) assert key0_casted_vote.validate(b_mock) @@ -103,10 +104,10 @@ def test_upsert_validator_invalid_election_vote(b_mock, valid_election, ed25519_ election_pub_key = ValidatorElection.to_public_key(valid_election.id) - vote = ValidatorElectionVote.generate([input0], - [([election_pub_key], votes+1)], - election_id=valid_election.id)\ - .sign([key0.private_key]) + vote = Vote.generate([input0], + [([election_pub_key], votes+1)], + election_id=valid_election.id)\ + .sign([key0.private_key]) with pytest.raises(AmountError): assert vote.validate(b_mock) @@ -125,10 +126,10 @@ def test_valid_election_votes_received(b_mock, valid_election, ed25519_node_keys 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]) + delegate_vote = Vote.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 @@ -136,10 +137,10 @@ def test_valid_election_votes_received(b_mock, valid_election, ed25519_node_keys 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]) + alice_casted_vote = Vote.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]) @@ -147,10 +148,10 @@ def test_valid_election_votes_received(b_mock, valid_election, ed25519_node_keys # 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]) + key0_casted_vote = Vote.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]) @@ -356,10 +357,10 @@ def to_inputs(election, i, ed25519_node_keys): def gen_vote(election, i, ed25519_node_keys): (input_i, votes_i, key_i) = to_inputs(election, i, ed25519_node_keys) election_pub_key = ValidatorElection.to_public_key(election.id) - return ValidatorElectionVote.generate([input_i], - [([election_pub_key], votes_i)], - election_id=election.id)\ - .sign([key_i.private_key]) + return Vote.generate([input_i], + [([election_pub_key], votes_i)], + election_id=election.id)\ + .sign([key_i.private_key]) def reset_validator_set(b, node_keys, height): From 30a5b9374d343bf8f943435a76d0f5314085778d Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 17:21:48 +0200 Subject: [PATCH 10/13] Problem: Error in docstring return signature Solution: Fixed the docstring --- bigchaindb/common/election.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index ddc92495..52d34b45 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -39,11 +39,8 @@ class Election(Transaction): :return: { 'height': , - 'asset': { - 'height': , - 'validators': , - 'election_id': - } + 'validators': , + 'election_id': } """ return bigchain.get_validator_change(height) From 7d756bf1a99c28096443fbf31353458b598306ef Mon Sep 17 00:00:00 2001 From: z-bowen Date: Tue, 4 Sep 2018 17:23:24 +0200 Subject: [PATCH 11/13] Problem: Hardcoded reference to the `VOTE_TYPE` in `Election` base class Solution: Pointed the reference to the class variable --- bigchaindb/common/election.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index 52d34b45..ed7bfa92 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -162,7 +162,7 @@ class Election(Transaction): def count_votes(cls, election_pk, transactions, getter=getattr): votes = 0 for txn in transactions: - if getter(txn, 'operation') == 'VOTE': + if getter(txn, 'operation') == cls.VOTE_TYPE: for output in getter(txn, 'outputs'): # NOTE: We enforce that a valid vote to election id will have only # election_pk in the output public keys, including any other public key From 331b52cc4c7c0c4cafd0614f0fb618e08ddaa64d Mon Sep 17 00:00:00 2001 From: z-bowen Date: Wed, 5 Sep 2018 10:36:44 +0200 Subject: [PATCH 12/13] Problem: Schema still refers to `ValidatorElectionVote` instead of `Vote` Solution: Renamed `TX_SCHEMA_VALIDATOR_ELECTION_VOTE` as `TX_SCHEMA_VOTE` --- bigchaindb/common/election.py | 2 +- bigchaindb/common/schema/__init__.py | 3 +-- ...r_election_vote_v2.0.yaml => transaction_vote_v2.0.yaml} | 2 +- bigchaindb/common/vote.py | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) rename bigchaindb/common/schema/{transaction_validator_election_vote_v2.0.yaml => transaction_vote_v2.0.yaml} (97%) diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index ed7bfa92..f43b743f 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -162,7 +162,7 @@ class Election(Transaction): def count_votes(cls, election_pk, transactions, getter=getattr): votes = 0 for txn in transactions: - if getter(txn, 'operation') == cls.VOTE_TYPE: + if getter(txn, 'operation') == cls.VOTE_TYPE.VOTE: for output in getter(txn, 'outputs'): # NOTE: We enforce that a valid vote to election id will have only # election_pk in the output public keys, including any other public key diff --git a/bigchaindb/common/schema/__init__.py b/bigchaindb/common/schema/__init__.py index 914e5196..25943675 100644 --- a/bigchaindb/common/schema/__init__.py +++ b/bigchaindb/common/schema/__init__.py @@ -37,8 +37,7 @@ _, TX_SCHEMA_TRANSFER = _load_schema('transaction_transfer_' + _, TX_SCHEMA_VALIDATOR_ELECTION = _load_schema('transaction_validator_election_' + TX_SCHEMA_VERSION) -_, TX_SCHEMA_VALIDATOR_ELECTION_VOTE = _load_schema('transaction_validator_election_vote_' + - TX_SCHEMA_VERSION) +_, TX_SCHEMA_VOTE = _load_schema('transaction_vote_' + TX_SCHEMA_VERSION) def _validate_schema(schema, body): diff --git a/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml b/bigchaindb/common/schema/transaction_vote_v2.0.yaml similarity index 97% rename from bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml rename to bigchaindb/common/schema/transaction_vote_v2.0.yaml index 5e7c4763..b2cf8d81 100644 --- a/bigchaindb/common/schema/transaction_validator_election_vote_v2.0.yaml +++ b/bigchaindb/common/schema/transaction_vote_v2.0.yaml @@ -12,7 +12,7 @@ required: properties: operation: type: string - value: "VOTE" + value: "OPERATION" outputs: type: array items: diff --git a/bigchaindb/common/vote.py b/bigchaindb/common/vote.py index 7b6230ba..67ed3444 100644 --- a/bigchaindb/common/vote.py +++ b/bigchaindb/common/vote.py @@ -6,7 +6,7 @@ from bigchaindb.common.transaction import Transaction from bigchaindb.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, - TX_SCHEMA_VALIDATOR_ELECTION_VOTE) + TX_SCHEMA_VOTE) class Vote(Transaction): @@ -45,14 +45,14 @@ class Vote(Transaction): @classmethod def validate_schema(cls, tx, skip_id=False): - """Validate the validator election vote transaction. Since `VALIDATOR_ELECTION_VOTE` extends `TRANFER` + """Validate the validator election vote transaction. Since `VOTE` extends `TRANSFER` transaction, all the validations for `CREATE` transaction should be inherited """ if not skip_id: cls.validate_id(tx) _validate_schema(TX_SCHEMA_COMMON, tx) _validate_schema(TX_SCHEMA_TRANSFER, tx) - _validate_schema(TX_SCHEMA_VALIDATOR_ELECTION_VOTE, tx) + _validate_schema(TX_SCHEMA_VOTE, tx) @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): From 0c64fbfb5df429ea204bdb367437cda83d49b2a1 Mon Sep 17 00:00:00 2001 From: z-bowen Date: Wed, 5 Sep 2018 10:41:05 +0200 Subject: [PATCH 13/13] Problem: `Election` class variable `ELECTION_TYPE` is overly specific Solution: Renamed `ELECTION_TYPE` to `OPERATION` --- bigchaindb/__init__.py | 2 +- bigchaindb/common/election.py | 4 ++-- bigchaindb/upsert_validator/validator_election.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index b63afa3d..2e4ef8b5 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -98,5 +98,5 @@ from bigchaindb.common.vote import Vote # noqa Transaction.register_type(Transaction.CREATE, models.Transaction) Transaction.register_type(Transaction.TRANSFER, models.Transaction) -Transaction.register_type(ValidatorElection.ELECTION_TYPE, ValidatorElection) +Transaction.register_type(ValidatorElection.OPERATION, ValidatorElection) Transaction.register_type(Vote.VOTE, Vote) diff --git a/bigchaindb/common/election.py b/bigchaindb/common/election.py index f43b743f..d9e907f9 100644 --- a/bigchaindb/common/election.py +++ b/bigchaindb/common/election.py @@ -23,7 +23,7 @@ class Election(Transaction): # NOTE: this transaction class extends create so the operation inheritance is achieved # by setting an ELECTION_TYPE and renaming CREATE = ELECTION_TYPE and ALLOWED_OPERATIONS = (ELECTION_TYPE,) - ELECTION_TYPE = None + OPERATION = None # the model for votes issued by the election VOTE_TYPE = Vote # Election Statuses: @@ -132,7 +132,7 @@ class Election(Transaction): @classmethod def generate(cls, initiator, voters, election_data, metadata=None): (inputs, outputs) = cls.validate_create(initiator, voters, election_data, metadata) - election = cls(cls.ELECTION_TYPE, {'data': election_data}, inputs, outputs, metadata) + election = cls(cls.OPERATION, {'data': election_data}, inputs, outputs, metadata) cls.validate_schema(election.to_dict(), skip_id=True) return election diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 0b94c71e..97e7a1ab 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -11,11 +11,11 @@ from .validator_utils import (new_validator_set, encode_validator) class ValidatorElection(Election): - ELECTION_TYPE = 'VALIDATOR_ELECTION' + OPERATION = 'VALIDATOR_ELECTION' # NOTE: this transaction class extends create so the operation inheritence is achieved # by renaming CREATE to VALIDATOR_ELECTION - CREATE = ELECTION_TYPE - ALLOWED_OPERATIONS = (ELECTION_TYPE,) + CREATE = OPERATION + ALLOWED_OPERATIONS = (OPERATION,) def validate(self, bigchain, current_transactions=[]): """For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21