Add signature options to validator signing

The JSON RPC API has changed and now demands a BLS signature
with the BLS key(s) to be added.
pull/35/head
MaxMustermann2 3 years ago
parent c81f9eff41
commit 4f266619fa
No known key found for this signature in database
GPG Key ID: 4F4AB9DB6FF24C94
  1. 5
      pyhmy/staking_signing.py
  2. 1
      pyhmy/staking_structures.py
  3. 55
      pyhmy/validator.py
  4. 20
      tests/sdk-pyhmy/test_validator.py

@ -271,6 +271,9 @@ def _sign_create_validator(transaction_dict, private_key):
bls_keys = apply_formatter_to_array( hexstr_if_str(to_bytes), # formatter
sanitized_transaction.pop('bls-public-keys')
)
bls_key_sigs = apply_formatter_to_array( hexstr_if_str(to_bytes), # formatter
sanitized_transaction.pop('bls-key-sigs')
)
sanitized_transaction['stakeMsg'] = \
apply_formatters_to_sequence( [
hexstr_if_str(to_bytes), # address
@ -279,6 +282,7 @@ def _sign_create_validator(transaction_dict, private_key):
hexstr_if_str(to_int), # min self delegation (in ONE), decimals are silently dropped
hexstr_if_str(to_int), # max total delegation (in ONE), decimals are silently dropped
identity, # bls public keys
identity, # bls key sigs
hexstr_if_str(to_int), # amount (the Hexlify in the SDK drops the decimals, which is what we will do too)
], [
convert_one_to_hex(sanitized_transaction.pop('validatorAddress')),
@ -287,6 +291,7 @@ def _sign_create_validator(transaction_dict, private_key):
math.floor(sanitized_transaction.pop('min-self-delegation')), # Decimal floors it correctly
math.floor(sanitized_transaction.pop('max-total-delegation')),
bls_keys,
bls_key_sigs,
math.floor(sanitized_transaction.pop('amount')),
]
)

@ -134,6 +134,7 @@ class CreateValidator:
big_endian_int, # min self delegation
big_endian_int, # max total delegation
CountableList(Binary.fixed_length(48, allow_empty=True)), # bls-public-keys array of unspecified length, each key of 48
CountableList(Binary.fixed_length(96, allow_empty=True)), # bls-key-sigs array of unspecified length, each sig of 96
big_endian_int, # amount
], True)), # strictly these number of elements
('nonce', big_endian_int),

@ -58,6 +58,7 @@ class Validator:
raise InvalidValidatorError(1, f'{address} is not valid ONE address')
self._address = address
self._bls_keys = []
self._bls_key_sigs = []
self._name = None
self._identity = None
@ -151,6 +152,47 @@ class Validator:
"""
return self._bls_keys
def add_bls_key_sig(self, key) -> bool:
"""
Add BLS public key to validator BLS keys if not already in list
Returns
-------
bool
If adding BLS key succeeded
"""
key = self._sanitize_input(key)
if key not in self._bls_key_sigs:
self._bls_key_sigs.append(key)
return True
return False
def remove_bls_key_sig(self, key) -> bool:
"""
Remove BLS public key from validator BLS keys if exists
Returns
-------
bool
If removing BLS key succeeded
"""
key = self._sanitize_input(key)
if key in self._bls_key_sigs:
self._bls_key_sigs.remove(key)
return True
return False
def get_bls_key_sigs(self) -> list:
"""
Get list of validator BLS keys
Returns
-------
list
List of validator BLS keys (strings)
"""
return self._bls_key_sigs
def set_name(self, name):
"""
Set validator name
@ -578,6 +620,7 @@ class Validator:
"max-rate": '0',
"max-change-rate": '0',
"bls-public-keys": [ "" ]
"bls-key-sigs": [ "" ]
}
Raises
@ -603,12 +646,18 @@ class Validator:
self._bls_keys = []
for key in info['bls-public-keys']:
self.add_bls_key(key)
self._bls_key_sigs = []
for key in info['bls-key-sigs']:
self.add_bls_key_sig(key)
except KeyError as e:
raise InvalidValidatorError(3, 'Info has missing key') from e
def load_from_blockchain(self, endpoint=_default_endpoint, timeout=_default_timeout):
"""
Import validator information from blockchain with given address
At the moment, this is unable to fetch the BLS Signature, which is not implemented
in the Node API
Parameters
----------
@ -674,7 +723,8 @@ class Validator:
"rate": self._rate,
"max-rate": self._max_rate,
"max-change-rate": self._max_change_rate,
"bls-public-keys": self._bls_keys
"bls-public-keys": self._bls_keys,
"bls-key-sigs": self._bls_key_sigs
}
return info
@ -705,7 +755,7 @@ class Validator:
info['chainId'] = chain_id
return sign_staking_transaction(info, private_key)
def sign_edit_validator_transaction(self, nonce, gas_price, gas_limit, rate, bls_key_to_add, bls_key_to_remove, private_key, chain_id=None) -> SignedTransaction:
def sign_edit_validator_transaction(self, nonce, gas_price, gas_limit, rate, bls_key_to_remove, bls_key_to_add, bls_key_to_add_sig, private_key, chain_id=None) -> SignedTransaction:
"""
Create but not post a transaction to Edit the Validator using private_key
@ -737,6 +787,7 @@ class Validator:
_ = info.pop('amount') # also unused
info['bls-key-to-remove'] = bls_key_to_remove
info['bls-key-to-add'] = bls_key_to_add
info['bls-key-to-add-sig'] = bls_key_to_add_sig
if chain_id:
info['chainId'] = chain_id
return sign_staking_transaction(info, private_key)

@ -49,7 +49,8 @@ def test_load_validator(setup_blockchain):
'max-rate': '0.9',
'max-change-rate': '0.05',
'rate': '0.01',
'bls-public-keys': ['0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611'],
'bls-public-keys': ['0x30b2c38b1316da91e068ac3bd8751c0901ef6c02a1d58bc712104918302c6ed03d5894671d0c816dad2b4d303320f202'],
'bls-key-sigs': ['0x68f800b6adf657b674903e04708060912b893b7c7b500788808247550ab3e186e56a44ebf3ca488f8ed1a42f6cef3a04bd5d2b2b7eb5a767848d3135b362e668ce6bba42c7b9d5666d8e3a83be707b5708e722c58939fe9b07c170f3b7062414'],
'max-total-delegation': convert_one_to_atto(40000)
}
test_validator_object.load(info)
@ -57,7 +58,9 @@ def test_load_validator(setup_blockchain):
test_validator_loaded = True
"""
TypeScript signature source
TypeScript signature source (is outdated because the JS SDK has not been updated for SlotKeySigs)
For now I have checked that the below transaction to localnet works
---
const description: Description = new Description('Alice', 'alice', 'alice.harmony.one', 'Bob', "Don't mess with me!!!")
const commissionRates: CommissionRate = new CommissionRate(new Decimal('0.01'), new Decimal('0.9'), new Decimal('0.05'))
const stakeMsg: CreateValidator = new CreateValidator(
@ -91,10 +94,12 @@ def test_create_validator_sign(setup_blockchain):
100,
'4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48',
None).rawTransaction.hex()
assert signed_hash == '0xf9010580f8bf94ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121dcc8872386f26fc10000c9880c7d713b49da0000c887b1a2bc2ec500008a021e19e0c9bab24000008a0878678326eac9000000f1b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b622476086118a021e27c1806e59a4000024a047c6d444971d4d3c48e8b255aa0e543ebb47b60f761582694e5af5330445aba5a04db1ffea9cca9f9e56e8f782c689db680992903acfd9c06f4593f7fd9a781bd7'
assert signed_hash == '0xf9016a80f9012394ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121dcc8872386f26fc10000c9880c7d713b49da0000c887b1a2bc2ec500008a021e19e0c9bab24000008a0878678326eac9000000f1b030b2c38b1316da91e068ac3bd8751c0901ef6c02a1d58bc712104918302c6ed03d5894671d0c816dad2b4d303320f202f862b86068f800b6adf657b674903e04708060912b893b7c7b500788808247550ab3e186e56a44ebf3ca488f8ed1a42f6cef3a04bd5d2b2b7eb5a767848d3135b362e668ce6bba42c7b9d5666d8e3a83be707b5708e722c58939fe9b07c170f3b70624148a021e27c1806e59a4000023a0650feed3d7bbcb9ed36575c829bfdc600d53cd7a4fcc0e78ddf26d740f1900a8a027798fc245ee5c66847327b7454670b3b84cb3998527c4fbc0f967b787f56bc2'
"""
Signature matched from TypeScript
Signature matched from TypeScript (is outdated because the JS SDK has not been updated for SlotKeyToAddSig)
For now I have checked that the below transaction to localnet works
---
import {
CreateValidator,
EditValidator,
@ -141,11 +146,12 @@ def test_edit_validator_sign(setup_blockchain):
int(convert_one_to_atto(1)),
100,
'0.06',
'0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608612', # add key
"0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611", # remove key
'0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608612', # remove key
"0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611", # add key
"0x68f800b6adf657b674903e04708060912b893b7c7b500788808247550ab3e186e56a44ebf3ca488f8ed1a42f6cef3a04bd5d2b2b7eb5a767848d3135b362e668ce6bba42c7b9d5666d8e3a83be707b5708e722c58939fe9b07c170f3b7062414", # add key sig
'4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48',
2).rawTransaction.hex()
assert signed_hash == '0xf9012101f8d094ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c887d529ae9e8600008a021e19e0c9bab24000008a0878678326eac9000000b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861202880de0b6b3a76400006428a0656d6741687ec1e42d1699274584a1777964e939b0ef11f3ff0e161859da21a2a03fc51e067f9fb6c96bee5ceccad4104f5b4b334a86a36a2f53d10b9a8e4a268a'
assert signed_hash == '0xf9012101f8d094ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c887d529ae9e8600008a021e19e0c9bab24000008a0878678326eac9000000b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608612b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861102880de0b6b3a76400006428a0782ed9f909b5c68eb050a917a274d9187a4c8f13799f21ba351bdcb11290c6c7a00a3b4ec8431290565acbbbb8231cafe32ed7c0b6211e7cf570b459cb733e0995'
@pytest.mark.run(order=4)
def test_invalid_validator(setup_blockchain):

Loading…
Cancel
Save