Merge branch 'abstract_election_class' into generalize-election-management-commands

This commit is contained in:
z-bowen 2018-09-05 17:26:47 +02:00
commit 35bd61c5d2
14 changed files with 56 additions and 57 deletions

View File

@ -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.common.vote import Vote # noqa
from bigchaindb.elections.vote import Vote # noqa
Transaction.register_type(Transaction.CREATE, models.Transaction)
Transaction.register_type(Transaction.TRANSFER, models.Transaction)
Transaction.register_type(ValidatorElection.OPERATION, ValidatorElection)
Transaction.register_type(Vote.VOTE, Vote)
Transaction.register_type(Vote.OPERATION, Vote)

View File

@ -282,7 +282,7 @@ def store_validator_set(conn, validators_update):
@register_query(LocalMongoDBConnection)
def store_election(conn, election):
def store_election_results(conn, election):
height = election['height']
return conn.run(
conn.collection('elections').replace_one(

View File

@ -143,6 +143,9 @@ def create_abci_chains_indexes(conn, dbname):
conn.conn[dbname]['abci_chains'].create_index('height',
name='height',
unique=True,)
conn.conn[dbname]['abci_chains'].create_index('chain_id',
name='chain_id',
unique=True)
def create_elections_secondary_index(conn, dbname):
@ -151,8 +154,3 @@ def create_elections_secondary_index(conn, dbname):
conn.conn[dbname]['elections'].create_index('election_id',
name='election_id',
unique=True,)
logger.info('Create `abci_chains.chain_id` secondary index.')
conn.conn[dbname]['abci_chains'].create_index('chain_id',
name='chain_id',
unique=True)

View File

@ -352,7 +352,7 @@ def store_validator_set(conn, validator_update):
@singledispatch
def store_election(conn, validator_update):
def store_election_results(conn, validator_update):
"""Store election results"""
raise NotImplementedError

View File

@ -17,7 +17,7 @@ from bigchaindb.utils import load_node_key
from bigchaindb.common.exceptions import (DatabaseAlreadyExists,
DatabaseDoesNotExist,
ValidationError)
from bigchaindb.common.vote import Vote
from bigchaindb.elections.vote import Vote
import bigchaindb
from bigchaindb import (backend, ValidatorElection,
BigchainDB)

View File

@ -12,7 +12,7 @@ required:
properties:
operation:
type: string
value: "OPERATION"
value: "VOTE"
outputs:
type: array
items:

View File

@ -209,9 +209,10 @@ class App(BaseApplication):
# Check if the current block concluded any validator elections and
# update the locally tracked validator set
validator_updates = ValidatorElection.is_approved(self.bigchaindb,
validator_update = ValidatorElection.approved_update(self.bigchaindb,
self.new_height,
self.block_transactions)
update = [validator_update] if validator_update else []
# Store pre-commit state to recover in case there is a crash
# during `commit`
@ -220,7 +221,7 @@ class App(BaseApplication):
transactions=self.block_txn_ids)
logger.debug('Updating PreCommitState: %s', self.new_height)
self.bigchaindb.store_pre_commit_state(pre_commit_state._asdict())
return ResponseEndBlock(validator_updates=validator_updates)
return ResponseEndBlock(validator_updates=update)
def commit(self):
"""Store the new height and along with block hash."""

View File

View File

@ -5,7 +5,7 @@
import base58
from bigchaindb import backend
from bigchaindb.common.vote import Vote
from bigchaindb.elections.vote import Vote
from bigchaindb.common.exceptions import (InvalidSignature,
MultipleInputsError,
InvalidProposer,
@ -26,6 +26,8 @@ class Election(Transaction):
OPERATION = None
# the model for votes issued by the election
VOTE_TYPE = Vote
# Custom validation schema
TX_SCHEMA_CUSTOM = None
# Election Statuses:
ONGOING = 'ongoing'
CONCLUDED = 'concluded'
@ -145,6 +147,8 @@ class Election(Transaction):
cls.validate_id(tx)
_validate_schema(TX_SCHEMA_COMMON, tx)
_validate_schema(TX_SCHEMA_CREATE, tx)
if cls.TX_SCHEMA_CUSTOM:
_validate_schema(cls.TX_SCHEMA_CUSTOM, tx)
@classmethod
def create(cls, tx_signers, recipients, metadata=None, asset=None):
@ -162,7 +166,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.VOTE:
if getter(txn, 'operation') == cls.VOTE_TYPE.OPERATION:
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
@ -221,8 +225,8 @@ class Election(Transaction):
return result
@classmethod
def store_election(cls, bigchain, election, height):
bigchain.store_election(height, election)
def store_election_results(cls, bigchain, election, height):
bigchain.store_election_results(height, election)
def show_election(self, bigchain):
data = self.asset['data']
@ -234,7 +238,7 @@ class Election(Transaction):
return response
@classmethod
def is_approved(cls, bigchain, new_height, txns):
def approved_update(cls, bigchain, new_height, txns):
votes = {}
for txn in txns:
if not isinstance(txn, cls.VOTE_TYPE):
@ -249,9 +253,9 @@ 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)
cls.store_election_results(bigchain, election, new_height)
return cls.on_approval(bigchain, election, new_height)
return []
return None
@classmethod
def on_approval(cls, bigchain, election, new_height):

View File

@ -11,11 +11,13 @@ from bigchaindb.common.schema import (_validate_schema,
class Vote(Transaction):
VOTE = 'VOTE'
OPERATION = 'VOTE'
# NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is
# overriden to re-use methods from parent class
TRANSFER = VOTE
ALLOWED_OPERATIONS = (VOTE,)
TRANSFER = OPERATION
ALLOWED_OPERATIONS = (OPERATION,)
# Custom validation schema
TX_SCHEMA_CUSTOM = TX_SCHEMA_VOTE
def validate(self, bigchain, current_transactions=[]):
"""Validate election vote transaction
@ -39,7 +41,7 @@ class Vote(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.VOTE, {'id': election_id}, inputs, outputs, metadata)
election_vote = cls(cls.OPERATION, {'id': election_id}, inputs, outputs, metadata)
cls.validate_schema(election_vote.to_dict(), skip_id=True)
return election_vote
@ -52,7 +54,7 @@ class Vote(Transaction):
cls.validate_id(tx)
_validate_schema(TX_SCHEMA_COMMON, tx)
_validate_schema(TX_SCHEMA_TRANSFER, tx)
_validate_schema(TX_SCHEMA_VOTE, tx)
_validate_schema(cls.TX_SCHEMA_CUSTOM, tx)
@classmethod
def create(cls, tx_signers, recipients, metadata=None, asset=None):

View File

@ -480,12 +480,12 @@ class BigchainDB(object):
self.store_abci_chain(block['height'] + 1, new_chain_id, False)
def store_election(self, height, election):
def store_election_results(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,
return backend.query.store_election_results(self.connection, {'height': height,
'election_id': election.id})

View File

@ -3,10 +3,9 @@
# Code is Apache-2.0 and docs are CC-BY-4.0
from bigchaindb.common.exceptions import InvalidPowerChange
from bigchaindb.common.election import Election
from bigchaindb.common.schema import (_validate_schema,
TX_SCHEMA_VALIDATOR_ELECTION)
from bigchaindb.tendermint_utils import public_key_to_base64
from bigchaindb.elections.election import Election
from bigchaindb.common.schema import (TX_SCHEMA_VALIDATOR_ELECTION)
from .validator_utils import (new_validator_set, encode_validator)
@ -17,6 +16,7 @@ class ValidatorElection(Election):
# by renaming CREATE to VALIDATOR_ELECTION
CREATE = OPERATION
ALLOWED_OPERATIONS = (OPERATION,)
TX_SCHEMA_CUSTOM = TX_SCHEMA_VALIDATOR_ELECTION
def validate(self, bigchain, current_transactions=[]):
"""For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21
@ -32,16 +32,6 @@ class ValidatorElection(Election):
return self
@classmethod
def validate_schema(cls, tx, skip_id=False):
"""Validate the validator election transaction. Since `VALIDATOR_ELECTION` extends `ELECTION`
transaction, all the validations for `ELECTION` transaction are covered by `super`
"""
super(ValidatorElection, cls).validate_schema(tx, skip_id=skip_id)
_validate_schema(TX_SCHEMA_VALIDATOR_ELECTION, tx)
@classmethod
def on_approval(cls, bigchain, election, new_height):
# The new validator set comes into effect from height = new_height+1
@ -52,7 +42,7 @@ class ValidatorElection(Election):
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 encode_validator(election.asset['data'])
def show_election(self, bigchain):

View File

@ -65,7 +65,7 @@ def concluded_election(b, ongoing_election, ed25519_node_keys):
election_result = {'height': 2,
'election_id': ongoing_election.id}
query.store_election(b.connection, election_result)
query.store_election_results(b.connection, election_result)
return ongoing_election

View File

@ -10,7 +10,7 @@ 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 bigchaindb.elections.vote import Vote
from tests.utils import generate_block
pytestmark = [pytest.mark.execute]
@ -300,19 +300,22 @@ 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.is_approved(b, 4, [tx_vote0]) == []
assert ValidatorElection.is_approved(b, 4, [tx_vote0, tx_vote1]) == []
assert not ValidatorElection.approved_update(b, 4, [tx_vote0])
assert not ValidatorElection.approved_update(b, 4, [tx_vote0, tx_vote1])
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
update = ValidatorElection.approved_update(b, 4, [tx_vote0, tx_vote1, tx_vote2])
update_public_key = None
if update:
update_public_key = codecs.encode(update.pub_key.data, 'base64').decode().rstrip('\n')
assert update
assert update_public_key == public_key64
b.store_bulk_transactions([tx_vote0, tx_vote1])
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
update = ValidatorElection.approved_update(b, 4, [tx_vote2])
if update:
update_public_key = codecs.encode(update.pub_key.data, 'base64').decode().rstrip('\n')
assert update
assert update_public_key == public_key64
# remove validator
@ -333,9 +336,10 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys):
b.store_bulk_transactions([tx_vote0, tx_vote1])
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
update = ValidatorElection.approved_update(b, 9, [tx_vote2])
if update:
update_public_key = codecs.encode(update.pub_key.data, 'base64').decode().rstrip('\n')
assert update
assert update_public_key == public_key64
# assert that the public key is not a part of the current validator set