diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 6b0793ba..d193ebb9 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -282,16 +282,26 @@ def store_validator_set(conn, validators_update): @register_query(LocalMongoDBConnection) -def store_election_results(conn, election): +def store_election(conn, election_id, height, is_concluded): return conn.run( conn.collection('elections').replace_one( - {'election_id': election['election_id']}, - election, + {'election_id': election_id, + 'height': height}, + {'election_id': election_id, + 'height': height, + 'is_concluded': is_concluded}, upsert=True, ) ) +@register_query(LocalMongoDBConnection) +def store_elections(conn, elections): + return conn.run( + conn.collection('elections').insert_many(elections) + ) + + @register_query(LocalMongoDBConnection) def get_validator_set(conn, height=None): query = {} @@ -312,13 +322,12 @@ def get_validator_set(conn, height=None): def get_election(conn, election_id): query = {'election_id': election_id} - cursor = conn.run( + return conn.run( conn.collection('elections') - .find(query, projection={'_id': False}) + .find_one(query, projection={'_id': False}, + sort=[('height', DESCENDING)]) ) - return next(cursor, None) - @register_query(LocalMongoDBConnection) def get_asset_tokens_for_public_key(conn, asset_id, public_key): diff --git a/bigchaindb/backend/localmongodb/schema.py b/bigchaindb/backend/localmongodb/schema.py index 053cfc3d..157ff39d 100644 --- a/bigchaindb/backend/localmongodb/schema.py +++ b/bigchaindb/backend/localmongodb/schema.py @@ -45,7 +45,8 @@ INDEXES = { ('commit_id', dict(name='pre_commit_id', unique=True)), ], 'elections': [ - ('election_id', dict(name='election_id', unique=True)), + ([('height', DESCENDING), ('election_id', ASCENDING)], + dict(name='election_id_height', unique=True)), ], 'validators': [ ('height', dict(name='height', unique=True)), diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index d8f60320..0b5bbade 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -352,8 +352,15 @@ def store_validator_set(conn, validator_update): @singledispatch -def store_election_results(conn, election): - """Store election results""" +def store_election(conn, election_id, height, is_concluded): + """Store election record""" + + raise NotImplementedError + + +@singledispatch +def store_elections(conn, elections): + """Store election records in bulk""" raise NotImplementedError @@ -369,7 +376,7 @@ def get_validator_set(conn, height): @singledispatch def get_election(conn, election_id): - """Return a validator set change with the specified election_id + """Return the election record """ raise NotImplementedError diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 34111c47..afe646bc 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -215,10 +215,9 @@ class App(BaseApplication): else: self.block_txn_hash = block['app_hash'] - # Process all concluded elections in the current block and get any update to the validator set - update = Election.approved_elections(self.bigchaindb, - self.new_height, - self.block_transactions) + validator_update = Election.process_block(self.bigchaindb, + self.new_height, + self.block_transactions) # Store pre-commit state to recover in case there is a crash during `commit` pre_commit_state = PreCommitState(commit_id=PRE_COMMIT_ID, @@ -226,7 +225,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=update) + return ResponseEndBlock(validator_updates=validator_update) def commit(self): """Store the new height and along with block hash.""" diff --git a/bigchaindb/elections/election.py b/bigchaindb/elections/election.py index 40861a52..e8b3256e 100644 --- a/bigchaindb/elections/election.py +++ b/bigchaindb/elections/election.py @@ -1,7 +1,7 @@ # 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 -from collections import defaultdict +from collections import OrderedDict import base58 from uuid import uuid4 @@ -22,9 +22,13 @@ from bigchaindb.common.schema import (_validate_schema, class Election(Transaction): + """Represents election transactions. + + To implement a custom election, create a class deriving from this one + with OPERATION set to the election operation, ALLOWED_OPERATIONS + set to (OPERATION,), CREATE set to OPERATION. + """ - # 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,) OPERATION = None # Custom validation schema TX_SCHEMA_CUSTOM = None @@ -34,7 +38,6 @@ class Election(Transaction): INCONCLUSIVE = 'inconclusive' # Vote ratio to approve an election ELECTION_THRESHOLD = 2 / 3 - CHANGES_VALIDATOR_SET = True @classmethod def get_validator_change(cls, bigchain): @@ -45,8 +48,10 @@ class Election(Transaction): 'validators': } """ - height = bigchain.get_latest_block()['height'] - return bigchain.get_validator_change(height) + latest_block = bigchain.get_latest_block() + if latest_block is None: + return None + return bigchain.get_validator_change(latest_block['height']) @classmethod def get_validators(cls, bigchain, height=None): @@ -186,49 +191,52 @@ class Election(Transaction): election_pk)) return self.count_votes(election_pk, txns, dict.get) - def has_concluded(self, bigchain, current_votes=[], height=None): + def has_concluded(self, bigchain, current_votes=[]): """Check if the election can be concluded or not. - * Elections can only be concluded if the current validator set - is exactly equal to the validator set encoded in the election outputs. + * Elections can only be concluded if the validator set has not changed + since the election was initiated. * Elections can be concluded only if the current votes form a supermajority. Custom elections may override this function and introduce additional checks. """ + if self.has_validator_set_changed(bigchain): + return False election_pk = self.to_public_key(self.id) votes_committed = self.get_commited_votes(bigchain, election_pk) votes_current = self.count_votes(election_pk, current_votes) - current_validators = self.get_validators(bigchain, height) - if self.is_same_topology(current_validators, self.outputs): - total_votes = sum(current_validators.values()) - if (votes_committed < (2/3) * total_votes) and \ - (votes_committed + votes_current >= (2/3)*total_votes): - return True + total_votes = sum(output.amount for output in self.outputs) + if (votes_committed < (2/3) * total_votes) and \ + (votes_committed + votes_current >= (2/3)*total_votes): + return True + return False def get_status(self, bigchain): - concluded = self.get_election(self.id, bigchain) - if concluded: + election = self.get_election(self.id, bigchain) + if election and election['is_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] + return self.INCONCLUSIVE if self.has_validator_set_changed(bigchain) else self.ONGOING - if latest_change_height >= election_height: - return self.INCONCLUSIVE - else: - return self.ONGOING + def has_validator_set_changed(self, bigchain): + latest_change = self.get_validator_change(bigchain) + if latest_change is None: + return False + + latest_change_height = latest_change['height'] + + election = self.get_election(self.id, bigchain) + + return latest_change_height > election['height'] def get_election(self, election_id, bigchain): - result = bigchain.get_election(election_id) - return result + return bigchain.get_election(election_id) - @classmethod - def store_election_results(cls, bigchain, election, height): - bigchain.store_election_results(height, election) + def store(self, bigchain, height, is_concluded): + bigchain.store_election(self.id, height, is_concluded) def show_election(self, bigchain): data = self.asset['data'] @@ -243,45 +251,61 @@ class Election(Transaction): return response @classmethod - def approved_elections(cls, bigchain, new_height, txns): - elections = defaultdict(list) + def process_block(cls, bigchain, new_height, txns): + """Looks for election and vote transactions inside the block, records + and processes elections. + + Every election is recorded in the database. + + Every vote has a chance to conclude the corresponding election. When + an election is concluded, the corresponding database record is + marked as such. + + Elections and votes are processed in the order in which they + appear in the block. Elections are concluded in the order of + appearance of their first votes in the block. + + For every election concluded in the block, calls its `on_approval` + method. The returned value of the last `on_approval`, if any, + is a validator set update to be applied in one of the following blocks. + + `on_approval` methods are implemented by elections of particular type. + The method may contain side effects but should be idempotent. To account + for other concluded elections, if it requires so, the method should + rely on the database state. + """ + # elections placed in this block + initiated_elections = [] + # elections voted for in this block and their votes + elections = OrderedDict() for tx in txns: + if isinstance(tx, Election): + initiated_elections.append({'election_id': tx.id, + 'height': new_height, + 'is_concluded': False}) if not isinstance(tx, Vote): continue election_id = tx.asset['id'] + if election_id not in elections: + elections[election_id] = [] elections[election_id].append(tx) - validator_set_updated = False - validator_set_change = [] + if initiated_elections: + bigchain.store_elections(initiated_elections) + + validator_update = None for election_id, votes in elections.items(): election = bigchain.get_transaction(election_id) if election is None: continue - if not election.has_concluded(bigchain, votes, new_height): + if not election.has_concluded(bigchain, votes): continue - if election.makes_validator_set_change(): - if validator_set_updated: - continue - validator_set_change.append(election.get_validator_set_change(bigchain, new_height)) - validator_set_updated = True + validator_update = election.on_approval(bigchain, new_height) + election.store(bigchain, new_height, is_concluded=True) - election.on_approval(bigchain, election, new_height) - election.store_election_results(bigchain, election, new_height) + return [validator_update] if validator_update else [] - return validator_set_change - - def makes_validator_set_change(self): - return self.CHANGES_VALIDATOR_SET - - def get_validator_set_change(self, bigchain, new_height): - if self.makes_validator_set_change(): - return self.change_validator_set(bigchain, new_height) - - def change_validator_set(self, bigchain, new_height): - raise NotImplementedError - - @classmethod - def on_approval(cls, bigchain, election, new_height): + def on_approval(self, bigchain, new_height): raise NotImplementedError diff --git a/bigchaindb/lib.py b/bigchaindb/lib.py index 974a7ac5..f38b0666 100644 --- a/bigchaindb/lib.py +++ b/bigchaindb/lib.py @@ -436,8 +436,7 @@ class BigchainDB(object): return [] if result is None else result['validators'] def get_election(self, election_id): - result = backend.query.get_election(self.connection, election_id) - return result + return backend.query.get_election(self.connection, election_id) def store_pre_commit_state(self, state): return backend.query.store_pre_commit_state(self.connection, state) @@ -481,13 +480,12 @@ class BigchainDB(object): self.store_abci_chain(block['height'] + 1, new_chain_id, False) - 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_results(self.connection, {'height': height, - 'election_id': election.id}) + def store_election(self, election_id, height, is_concluded): + return backend.query.store_election(self.connection, election_id, + height, is_concluded) + + def store_elections(self, elections): + return backend.query.store_elections(self.connection, elections) Block = namedtuple('Block', ('app_hash', 'height', 'transactions')) diff --git a/bigchaindb/migrations/chain_migration_election.py b/bigchaindb/migrations/chain_migration_election.py index 8e80b979..129e6684 100644 --- a/bigchaindb/migrations/chain_migration_election.py +++ b/bigchaindb/migrations/chain_migration_election.py @@ -8,7 +8,6 @@ class ChainMigrationElection(Election): CREATE = OPERATION ALLOWED_OPERATIONS = (OPERATION,) TX_SCHEMA_CUSTOM = TX_SCHEMA_CHAIN_MIGRATION_ELECTION - CHANGES_VALIDATOR_SET = False def has_concluded(self, bigchaindb, *args, **kwargs): chain = bigchaindb.get_latest_abci_chain() @@ -19,6 +18,5 @@ class ChainMigrationElection(Election): return super().has_concluded(bigchaindb, *args, **kwargs) - @classmethod - def on_approval(cls, bigchain, election, new_height): + def on_approval(self, bigchain, *args, **kwargs): bigchain.migrate_abci_chain() diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 856b31a1..27e0ff56 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -36,18 +36,28 @@ class ValidatorElection(Election): super(ValidatorElection, cls).validate_schema(tx) validate_asset_public_key(tx['asset']['data']['public_key']) - def change_validator_set(self, bigchain, new_height): - # The new validator set comes into effect from height = new_height+1 - # (upcoming changes to Tendermint will change this to height = new_height+2) + def has_concluded(self, bigchain, *args, **kwargs): + latest_block = bigchain.get_latest_block() + if latest_block is not None: + latest_block_height = latest_block['height'] + latest_validator_change = bigchain.get_validator_change()['height'] + + # TODO change to `latest_block_height + 3` when upgrading to Tendermint 0.24.0. + if latest_validator_change == latest_block_height + 2: + # do not conclude the election if there is a change assigned already + return False + + return super().has_concluded(bigchain, *args, **kwargs) + + def on_approval(self, bigchain, new_height): validator_updates = [self.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) - return encode_validator(self.asset['data']) + updated_validator_set = [v for v in updated_validator_set + if v['voting_power'] > 0] - @classmethod - def on_approval(cls, bigchain, election, new_height): - pass + # TODO change to `new_height + 2` when upgrading to Tendermint 0.24.0. + bigchain.store_validator_set(new_height + 1, updated_validator_set) + return encode_validator(self.asset['data']) diff --git a/tests/backend/localmongodb/test_schema.py b/tests/backend/localmongodb/test_schema.py index a96e7b63..c4f6669a 100644 --- a/tests/backend/localmongodb/test_schema.py +++ b/tests/backend/localmongodb/test_schema.py @@ -3,51 +3,6 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 -def test_init_creates_db_tables_and_indexes(): - import bigchaindb - from bigchaindb import backend - from bigchaindb.backend.schema import init_database - - conn = backend.connect() - dbname = bigchaindb.config['database']['name'] - - # the db is set up by the fixture so we need to remove it - conn.conn.drop_database(dbname) - - init_database() - - collection_names = conn.conn[dbname].list_collection_names() - assert set(collection_names) == { - 'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'pre_commit', - 'validators', 'elections', 'abci_chains', - } - - indexes = conn.conn[dbname]['assets'].index_information().keys() - assert set(indexes) == {'_id_', 'asset_id', 'text'} - - indexes = conn.conn[dbname]['transactions'].index_information().keys() - assert set(indexes) == { - '_id_', 'transaction_id', 'asset_id', 'outputs', 'inputs'} - - indexes = conn.conn[dbname]['blocks'].index_information().keys() - assert set(indexes) == {'_id_', 'height'} - - indexes = conn.conn[dbname]['utxos'].index_information().keys() - assert set(indexes) == {'_id_', 'utxo'} - - indexes = conn.conn[dbname]['pre_commit'].index_information().keys() - assert set(indexes) == {'_id_', 'pre_commit_id'} - - indexes = conn.conn[dbname]['validators'].index_information().keys() - assert set(indexes) == {'_id_', 'height'} - - indexes = conn.conn[dbname]['abci_chains'].index_information().keys() - assert set(indexes) == {'_id_', 'height', 'chain_id'} - - indexes = conn.conn[dbname]['elections'].index_information().keys() - assert set(indexes) == {'_id_', 'election_id'} - - def test_init_database_is_graceful_if_db_exists(): import bigchaindb from bigchaindb import backend @@ -102,8 +57,8 @@ def test_create_tables(): ('output_index', 1)] indexes = conn.conn[dbname]['elections'].index_information() - assert set(indexes.keys()) == {'_id_', 'election_id'} - assert indexes['election_id']['unique'] + assert set(indexes.keys()) == {'_id_', 'election_id_height'} + assert indexes['election_id_height']['unique'] indexes = conn.conn[dbname]['pre_commit'].index_information() assert set(indexes.keys()) == {'_id_', 'pre_commit_id'} diff --git a/tests/conftest.py b/tests/conftest.py index e001465c..a96d843f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -712,12 +712,13 @@ def valid_upsert_validator_election_2(b_mock, node_key, new_validator): def ongoing_validator_election(b, valid_upsert_validator_election, ed25519_node_keys): validators = b.get_validators(height=1) genesis_validators = {'validators': validators, - 'height': 0, - 'election_id': None} + 'height': 0} query.store_validator_set(b.connection, genesis_validators) - b.store_bulk_transactions([valid_upsert_validator_election]) - block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_upsert_validator_election.id]) + query.store_election(b.connection, valid_upsert_validator_election.id, 1, + is_concluded=False) + block_1 = Block(app_hash='hash_1', height=1, + transactions=[valid_upsert_validator_election.id]) b.store_block(block_1._asdict()) return valid_upsert_validator_election diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index 0aed1816..a8c5ce98 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -9,7 +9,7 @@ from bigchaindb.upsert_validator.validator_election import ValidatorElection @pytest.mark.bdb -def test_approved_elections_concludes_all_elections(b): +def test_process_block_concludes_all_elections(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) @@ -17,28 +17,30 @@ def test_approved_elections_concludes_all_elections(b): public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] - election, votes = generate_election(b, - ValidatorElection, - public_key, private_key, - new_validator['election']) - txs = [election] - total_votes = votes election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}) + txs = [election] + total_votes = votes + + election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + new_validator['election']) txs += [election] total_votes += votes b.store_abci_chain(1, 'chain-X') + Election.process_block(b, 1, txs) b.store_block(Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) - Election.approved_elections(b, 1, total_votes) + Election.process_block(b, 2, total_votes) validators = b.get_validators() assert len(validators) == 5 @@ -53,12 +55,11 @@ def test_approved_elections_concludes_all_elections(b): } for tx in txs: - election = b.get_election(tx.id) - assert election + assert b.get_election(tx.id)['is_concluded'] @pytest.mark.bdb -def test_approved_elections_applies_only_one_validator_update(b): +def test_process_block_approves_only_one_validator_update(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) @@ -82,24 +83,123 @@ def test_approved_elections_applies_only_one_validator_update(b): txs += [election] total_votes += votes + Election.process_block(b, 1, txs) b.store_block(Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) - Election.approved_elections(b, 1, total_votes) + Election.process_block(b, 2, total_votes) validators = b.get_validators() assert len(validators) == 5 assert new_validator['storage'] in validators assert another_validator['storage'] not in validators - assert b.get_election(txs[0].id) - assert not b.get_election(txs[1].id) + assert b.get_election(txs[0].id)['is_concluded'] + assert not b.get_election(txs[1].id)['is_concluded'] @pytest.mark.bdb -def test_approved_elections_applies_only_one_migration(b): +def test_process_block_approves_after_pending_validator_update(b): + validators = generate_validators([1] * 4) + b.store_validator_set(1, [v['storage'] for v in validators]) + + new_validator = generate_validators([1])[0] + + public_key = validators[0]['public_key'] + private_key = validators[0]['private_key'] + election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + new_validator['election']) + txs = [election] + total_votes = votes + + another_validator = generate_validators([1])[0] + + election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + another_validator['election']) + txs += [election] + total_votes += votes + + election, votes = generate_election(b, + ChainMigrationElection, + public_key, private_key, + {}) + + txs += [election] + total_votes += votes + + b.store_abci_chain(1, 'chain-X') + Election.process_block(b, 1, txs) + b.store_block(Block(height=1, + transactions=[tx.id for tx in txs], + app_hash='')._asdict()) + b.store_bulk_transactions(txs) + + Election.process_block(b, 2, total_votes) + + validators = b.get_validators() + assert len(validators) == 5 + assert new_validator['storage'] in validators + assert another_validator['storage'] not in validators + + assert b.get_election(txs[0].id)['is_concluded'] + assert not b.get_election(txs[1].id)['is_concluded'] + assert b.get_election(txs[2].id)['is_concluded'] + + assert b.get_latest_abci_chain() == {'height': 2, + 'chain_id': 'chain-X-migrated-at-height-1', + 'is_synced': False} + + +@pytest.mark.bdb +def test_process_block_does_not_approve_after_validator_update(b): + validators = generate_validators([1] * 4) + b.store_validator_set(1, [v['storage'] for v in validators]) + + new_validator = generate_validators([1])[0] + + public_key = validators[0]['public_key'] + private_key = validators[0]['private_key'] + election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + new_validator['election']) + txs = [election] + total_votes = votes + + b.store_block(Block(height=1, + transactions=[tx.id for tx in txs], + app_hash='')._asdict()) + Election.process_block(b, 1, txs) + b.store_bulk_transactions(txs) + + second_election, second_votes = generate_election(b, + ChainMigrationElection, + public_key, private_key, + {}) + + Election.process_block(b, 2, total_votes + [second_election]) + + b.store_block(Block(height=2, + transactions=[v.id for v in total_votes + [second_election]], + app_hash='')._asdict()) + + b.store_abci_chain(1, 'chain-X') + Election.process_block(b, 3, second_votes) + + assert not b.get_election(second_election.id)['is_concluded'] + assert b.get_latest_abci_chain() == {'height': 1, + 'chain_id': 'chain-X', + 'is_synced': True} + + +@pytest.mark.bdb +def test_process_block_applies_only_one_migration(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) @@ -121,12 +221,13 @@ def test_approved_elections_applies_only_one_migration(b): total_votes += votes b.store_abci_chain(1, 'chain-X') + Election.process_block(b, 1, txs) b.store_block(Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) - Election.approved_elections(b, 1, total_votes) + Election.process_block(b, 1, total_votes) chain = b.get_latest_abci_chain() assert chain assert chain == { @@ -135,9 +236,9 @@ def test_approved_elections_applies_only_one_migration(b): 'chain_id': 'chain-X-migrated-at-height-1', } - assert b.get_election(txs[0].id) - assert not b.get_election(txs[1].id) + assert b.get_election(txs[0].id)['is_concluded'] + assert not b.get_election(txs[1].id)['is_concluded'] -def test_approved_elections_gracefully_handles_empty_block(b): - Election.approved_elections(b, 1, []) +def test_process_block_gracefully_handles_empty_block(b): + Election.process_block(b, 1, []) diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index 58b5e6dd..c39b9ed3 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -28,10 +28,8 @@ def fixed_seed_election(b_mock, node_key, new_validator): @pytest.fixture def concluded_election(b, ongoing_validator_election, ed25519_node_keys): - election_result = {'height': 2, - 'election_id': ongoing_validator_election.id} - - query.store_election_results(b.connection, election_result) + query.store_election(b.connection, ongoing_validator_election.id, + 2, is_concluded=True) return ongoing_validator_election diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index 7c49bd77..eeac3e66 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -289,10 +289,10 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): assert not election.has_concluded(b, [tx_vote0, tx_vote1]) assert election.has_concluded(b, [tx_vote0, tx_vote1, tx_vote2]) - assert Election.approved_elections(b, 4, [tx_vote0]) == [] - assert Election.approved_elections(b, 4, [tx_vote0, tx_vote1]) == [] + assert Election.process_block(b, 4, [tx_vote0]) == [] + assert Election.process_block(b, 4, [tx_vote0, tx_vote1]) == [] - update = Election.approved_elections(b, 4, [tx_vote0, tx_vote1, tx_vote2]) + update = Election.process_block(b, 4, [tx_vote0, tx_vote1, tx_vote2]) assert len(update) == 1 update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') assert update_public_key == public_key64 @@ -315,7 +315,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): b.store_bulk_transactions([tx_vote0, tx_vote1]) - update = Election.approved_elections(b, 9, [tx_vote2]) + update = Election.process_block(b, 9, [tx_vote2]) assert len(update) == 1 update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') assert update_public_key == public_key64