From 0a7eeaaf26a55de43de6c9ecddef8ae162241f24 Mon Sep 17 00:00:00 2001 From: Vanshdeep Singh Date: Wed, 5 Sep 2018 15:07:30 +0200 Subject: [PATCH] Problem: Public key not encoded using type in validator set update Solution: Use `value` field to use appropriate decoder and re-encode public key in base16 --- bigchaindb/common/exceptions.py | 2 +- .../transaction_validator_election_v2.0.yaml | 4 +++ .../upsert_validator/validator_election.py | 6 +++- .../upsert_validator/validator_utils.py | 34 ++++++++++++++----- tests/commands/test_commands.py | 1 - 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/bigchaindb/common/exceptions.py b/bigchaindb/common/exceptions.py index b2fc970d..099ef92e 100644 --- a/bigchaindb/common/exceptions.py +++ b/bigchaindb/common/exceptions.py @@ -115,4 +115,4 @@ class InvalidPowerChange(ValidationError): class InvalidPublicKey(ValidationError): - """Raised if proposed power change in validator set is >=1/3 total power""" + """Raised if public key doesn't match the encoding type""" diff --git a/bigchaindb/common/schema/transaction_validator_election_v2.0.yaml b/bigchaindb/common/schema/transaction_validator_election_v2.0.yaml index 9041a991..d849d516 100644 --- a/bigchaindb/common/schema/transaction_validator_election_v2.0.yaml +++ b/bigchaindb/common/schema/transaction_validator_election_v2.0.yaml @@ -33,6 +33,10 @@ properties: type: string type: type: string + enum: + - ed25519-base16 + - ed25519-base32 + - ed25519-base64 power: "$ref": "#/definitions/positiveInteger" required: diff --git a/bigchaindb/upsert_validator/validator_election.py b/bigchaindb/upsert_validator/validator_election.py index 0bf052ad..0b36c268 100644 --- a/bigchaindb/upsert_validator/validator_election.py +++ b/bigchaindb/upsert_validator/validator_election.py @@ -21,6 +21,7 @@ from bigchaindb.common.schema import (_validate_schema, from . import ValidatorElectionVote from .validator_utils import (new_validator_set, encode_validator, + encode_pk_to_base16, validate_asset_public_key) @@ -239,7 +240,10 @@ class ValidatorElection(Transaction): 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'])] + + validator16 = encode_pk_to_base16(election.asset['data']) + return [encode_validator(validator16)] + return [] def get_validator_update_by_election_id(self, election_id, bigchain): diff --git a/bigchaindb/upsert_validator/validator_utils.py b/bigchaindb/upsert_validator/validator_utils.py index a2849c64..fe0493fc 100644 --- a/bigchaindb/upsert_validator/validator_utils.py +++ b/bigchaindb/upsert_validator/validator_utils.py @@ -31,7 +31,8 @@ def new_validator_set(validators, updates): updates_dict = {} for u in updates: - public_key64 = public_key_to_base64(u['public_key']['value']) + 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']} @@ -40,7 +41,28 @@ def new_validator_set(validators, updates): return list(new_validators_dict.values()) +def encode_pk_to_base16(validator): + pk = validator['public_key'] + decoder = get_public_key_decoder(pk) + public_key16 = base64.b16encode(decoder(pk['value'])).decode('utf-8') + + validator['public_key']['value'] = public_key16 + return validator + + def validate_asset_public_key(pk): + pk_binary = pk['value'].encode('utf-8') + decoder = get_public_key_decoder(pk) + try: + pk_decoded = decoder(pk_binary) + if len(pk_decoded) != 32: + raise InvalidPublicKey('Public key should be of size 32 bytes') + + except binascii.Error as e: + raise InvalidPublicKey('Invalid `type` specified for public key `value`') + + +def get_public_key_decoder(pk): pk_binary = pk['value'].encode('utf-8') encoding = pk['type'] decoder = base64.b64decode @@ -51,11 +73,7 @@ def validate_asset_public_key(pk): decoder = base64.b32decode elif encoding == 'ed25519-base64': decoder = base64.b64decode - - try: - pk_decoded = decoder(pk_binary) - if len(pk_decoded) != 32: - raise InvalidPublicKey('Public key should be of size 32 bytes') - - except binascii.Error as e: + else: raise InvalidPublicKey('Invalid `type` specified for public key `value`') + + return decoder diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b530fd4c..d669962e 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -429,7 +429,6 @@ def test_upsert_validator_new_election_invalid_power(caplog, b, priv_validator_p assert caplog.records[0].msg.__class__ == InvalidPowerChange -@pytest.mark.google @pytest.mark.abci def test_upsert_validator_approve_with_tendermint(b, priv_validator_path, user_sk, validators): from bigchaindb.commands.bigchaindb import (run_upsert_validator_new,