From db7d9663f12cb144abc31f733e598dbd42708782 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 10 Oct 2022 13:35:04 +0200 Subject: [PATCH] moved some validator utils to tendermint utils, election approval now handled by planetmint Signed-off-by: Lorenz Herzberger --- planetmint/core.py | 6 +-- planetmint/lib.py | 23 ++++++-- planetmint/tendermint_utils.py | 54 +++++++++++++++++++ .../elections/chain_migration_election.py | 4 -- .../transactions/types/elections/election.py | 7 --- .../types/elections/validator_election.py | 13 +---- .../types/elections/validator_utils.py | 38 ------------- tests/tendermint/test_core.py | 3 +- 8 files changed, 78 insertions(+), 70 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index bc123dd..1776528 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -21,10 +21,8 @@ from tendermint.abci.types_pb2 import ( ResponseCommit, ) from planetmint import Planetmint -from planetmint.transactions.types.elections.election import Election -from planetmint.tendermint_utils import decode_transaction, calculate_hash +from planetmint.tendermint_utils import decode_transaction, calculate_hash, decode_validator from planetmint.lib import Block -import planetmint.transactions.types.elections.validator_utils as vutils from planetmint.events import EventTypes, Event @@ -87,7 +85,7 @@ class App(BaseApplication): app_hash = "" if block is None else block["app_hash"] height = 0 if block is None else block["height"] + 1 known_validators = self.planetmint_node.get_validators() - validator_set = [vutils.decode_validator(v) for v in genesis.validators] + validator_set = [decode_validator(v) for v in genesis.validators] if known_validators and known_validators != validator_set: self.log_abci_migration_error(known_chain["chain_id"], known_validators) sys.exit(1) diff --git a/planetmint/lib.py b/planetmint/lib.py index f44fdcf..d63afe4 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -43,7 +43,7 @@ from planetmint.transactions.common.transaction_mode_types import ( BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC, ) -from planetmint.tendermint_utils import encode_transaction, merkleroot, key_from_base64, public_key_to_base64 +from planetmint.tendermint_utils import encode_transaction, merkleroot, key_from_base64, public_key_to_base64, encode_validator, new_validator_set from planetmint import exceptions as core_exceptions from planetmint.transactions.types.elections.election import Election from planetmint.transactions.types.elections.vote import Vote @@ -874,7 +874,7 @@ class Planetmint(object): if not self.has_election_concluded(election, votes): continue - validator_update = election.on_approval(self, new_height) + validator_update = self.approve_election(election, new_height) self.store_election(election.id, new_height, is_concluded=True) return [validator_update] if validator_update else [] @@ -947,11 +947,28 @@ class Planetmint(object): elections = self._get_votes(txns) for election_id in elections: election = self.get_transaction(election_id) - # election.on_rollback(self, new_height) if election.operation == VALIDATOR_ELECTION: # TODO change to `new_height + 2` when upgrading to Tendermint 0.24.0. self.delete_validator_set(new_height + 1) if election.operation == CHAIN_MIGRATION_ELECTION: self.delete_abci_chain(new_height) + def approve_election(self, election, new_height): + """Override to update the database state according to the + election rules. Consider the current database state to account for + other concluded elections, if required. + """ + if election.operation == CHAIN_MIGRATION_ELECTION: + self.migrate_abci_chain() + if election.operation == VALIDATOR_ELECTION: + validator_updates = [election.asset["data"]] + curr_validator_set = self.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] + + # TODO change to `new_height + 2` when upgrading to Tendermint 0.24.0. + self.store_validator_set(new_height + 1, updated_validator_set) + return encode_validator(election.asset["data"]) + Block = namedtuple("Block", ("app_hash", "height", "transactions")) diff --git a/planetmint/tendermint_utils.py b/planetmint/tendermint_utils.py index ad7bb66..7daef69 100644 --- a/planetmint/tendermint_utils.py +++ b/planetmint/tendermint_utils.py @@ -6,10 +6,64 @@ import base64 import hashlib import json +import codecs + from binascii import hexlify +from tendermint.abci import types_pb2 +from tendermint.crypto import keys_pb2 from hashlib import sha3_256 +from planetmint.transactions.common.exceptions import InvalidPublicKey + +def encode_validator(v): + ed25519_public_key = v["public_key"]["value"] + pub_key = keys_pb2.PublicKey(ed25519=bytes.fromhex(ed25519_public_key)) + + return types_pb2.ValidatorUpdate(pub_key=pub_key, power=v["power"]) + + +def decode_validator(v): + return { + "public_key": { + "type": "ed25519-base64", + "value": codecs.encode(v.pub_key.ed25519, "base64").decode().rstrip("\n"), + }, + "voting_power": v.power, + } + + +def new_validator_set(validators, updates): + validators_dict = {} + for v in validators: + validators_dict[v["public_key"]["value"]] = v + + updates_dict = {} + for u in updates: + decoder = get_public_key_decoder(u["public_key"]) + public_key64 = base64.b64encode(decoder(u["public_key"]["value"])).decode("utf-8") + updates_dict[public_key64] = { + "public_key": {"type": "ed25519-base64", "value": public_key64}, + "voting_power": u["power"], + } + + new_validators_dict = {**validators_dict, **updates_dict} + return list(new_validators_dict.values()) + +def get_public_key_decoder(pk): + encoding = pk["type"] + decoder = base64.b64decode + + if encoding == "ed25519-base16": + decoder = base64.b16decode + elif encoding == "ed25519-base32": + decoder = base64.b32decode + elif encoding == "ed25519-base64": + decoder = base64.b64decode + else: + raise InvalidPublicKey("Invalid `type` specified for public key `value`") + + return decoder def encode_transaction(value): """Encode a transaction (dict) to Base64.""" diff --git a/planetmint/transactions/types/elections/chain_migration_election.py b/planetmint/transactions/types/elections/chain_migration_election.py index 58257d3..014843f 100644 --- a/planetmint/transactions/types/elections/chain_migration_election.py +++ b/planetmint/transactions/types/elections/chain_migration_election.py @@ -11,9 +11,5 @@ from planetmint.transactions.types.elections.election import Election class ChainMigrationElection(Election): OPERATION = CHAIN_MIGRATION_ELECTION - # CREATE = OPERATION ALLOWED_OPERATIONS = (OPERATION,) TX_SCHEMA_CUSTOM = TX_SCHEMA_CHAIN_MIGRATION_ELECTION - - def on_approval(self, planet, *args, **kwargs): # TODO: move somewhere else - planet.migrate_abci_chain() diff --git a/planetmint/transactions/types/elections/election.py b/planetmint/transactions/types/elections/election.py index c4773c8..51af81f 100644 --- a/planetmint/transactions/types/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -66,10 +66,3 @@ class Election(Transaction): _validate_schema(TX_SCHEMA_COMMON, tx) if cls.TX_SCHEMA_CUSTOM: _validate_schema(cls.TX_SCHEMA_CUSTOM, tx) - - def on_approval(self, planet, new_height): - """Override to update the database state according to the - election rules. Consider the current database state to account for - other concluded elections, if required. - """ - raise NotImplementedError diff --git a/planetmint/transactions/types/elections/validator_election.py b/planetmint/transactions/types/elections/validator_election.py index 670060c..cc87487 100644 --- a/planetmint/transactions/types/elections/validator_election.py +++ b/planetmint/transactions/types/elections/validator_election.py @@ -7,7 +7,7 @@ from planetmint.transactions.types.elections.election import Election from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION from planetmint.transactions.common.transaction import VALIDATOR_ELECTION -from .validator_utils import new_validator_set, encode_validator, validate_asset_public_key +from .validator_utils import validate_asset_public_key class ValidatorElection(Election): @@ -20,14 +20,3 @@ class ValidatorElection(Election): def validate_schema(cls, tx): super(ValidatorElection, cls).validate_schema(tx) validate_asset_public_key(tx["asset"]["data"]["public_key"]) - - def on_approval(self, planet, new_height): # TODO: move somewhere else - validator_updates = [self.asset["data"]] - curr_validator_set = planet.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] - - # TODO change to `new_height + 2` when upgrading to Tendermint 0.24.0. - planet.store_validator_set(new_height + 1, updated_validator_set) - return encode_validator(self.asset["data"]) diff --git a/planetmint/transactions/types/elections/validator_utils.py b/planetmint/transactions/types/elections/validator_utils.py index 338a6b3..b9e801c 100644 --- a/planetmint/transactions/types/elections/validator_utils.py +++ b/planetmint/transactions/types/elections/validator_utils.py @@ -6,48 +6,10 @@ import base58 import base64 import binascii -import codecs -from tendermint.abci import types_pb2 -from tendermint.crypto import keys_pb2 from planetmint.transactions.common.exceptions import InvalidPublicKey -def encode_validator(v): - ed25519_public_key = v["public_key"]["value"] - pub_key = keys_pb2.PublicKey(ed25519=bytes.fromhex(ed25519_public_key)) - - return types_pb2.ValidatorUpdate(pub_key=pub_key, power=v["power"]) - - -def decode_validator(v): - return { - "public_key": { - "type": "ed25519-base64", - "value": codecs.encode(v.pub_key.ed25519, "base64").decode().rstrip("\n"), - }, - "voting_power": v.power, - } - - -def new_validator_set(validators, updates): - validators_dict = {} - for v in validators: - validators_dict[v["public_key"]["value"]] = v - - updates_dict = {} - for u in updates: - decoder = get_public_key_decoder(u["public_key"]) - public_key64 = base64.b64encode(decoder(u["public_key"]["value"])).decode("utf-8") - updates_dict[public_key64] = { - "public_key": {"type": "ed25519-base64", "value": public_key64}, - "voting_power": u["power"], - } - - new_validators_dict = {**validators_dict, **updates_dict} - return list(new_validators_dict.values()) - - def encode_pk_to_base16(validator): pk = validator["public_key"] decoder = get_public_key_decoder(pk) diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 4c8d9f5..bf715b5 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -16,11 +16,10 @@ from planetmint import App from planetmint.backend import query from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import OkCode, CodeTypeError, rollback -from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection from planetmint.transactions.types.elections.validator_election import ValidatorElection -from planetmint.transactions.types.elections.validator_utils import new_validator_set +from planetmint.tendermint_utils import new_validator_set from planetmint.tendermint_utils import public_key_to_base64 from planetmint.version import __tm_supported_versions__