From 0a7f9bb88e4af2278a874550c200530231907367 Mon Sep 17 00:00:00 2001 From: cyc60 Date: Tue, 22 Aug 2023 13:40:07 +0300 Subject: [PATCH] Cache validator registration request while deposit root not changed Signed-off-by: cyc60 --- src/validators/execution.py | 13 +++++---- src/validators/tasks.py | 53 +++++++++++++++++++++++++++---------- src/validators/typings.py | 3 ++- src/validators/utils.py | 2 +- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/validators/execution.py b/src/validators/execution.py index 3e8ea1ac..31721373 100644 --- a/src/validators/execution.py +++ b/src/validators/execution.py @@ -10,6 +10,7 @@ get_eth1_withdrawal_credentials, is_valid_deposit_data_signature, ) +from sw_utils.typings import Bytes32 from web3 import Web3 from web3.types import EventData, Wei @@ -225,6 +226,7 @@ async def register_single_validator( validator: Validator, approval: OraclesApproval, update_state_call: HexStr | None, + validators_registry_root: Bytes32, ) -> None: """Registers single validator.""" if settings.network not in ETH_NETWORKS: @@ -237,7 +239,7 @@ async def register_single_validator( logger.info('Submitting registration transaction') register_call_args = [ ( - approval.validators_registry_root, + validators_registry_root, tx_validator, approval.signatures, approval.ipfs_hash, @@ -262,7 +264,8 @@ async def register_multiple_validator( tree: StandardMerkleTree, validators: list[Validator], approval: OraclesApproval, - update_call: HexStr | None, + update_state_call: HexStr | None, + validators_registry_root: Bytes32, ) -> None: """Registers multiple validators.""" if settings.network not in ETH_NETWORKS: @@ -283,7 +286,7 @@ async def register_multiple_validator( logger.info('Submitting registration transaction') register_call_args = [ ( - approval.validators_registry_root, + validators_registry_root, b''.join(tx_validators), approval.signatures, approval.ipfs_hash, @@ -292,12 +295,12 @@ async def register_multiple_validator( multi_proof.proof_flags, multi_proof.proof, ] - if update_call is not None: + if update_state_call is not None: register_call = vault_contract.encodeABI( fn_name='registerValidators', args=register_call_args, ) - tx = await vault_contract.functions.multicall([update_call, register_call]).transact() + tx = await vault_contract.functions.multicall([update_state_call, register_call]).transact() else: tx = await vault_contract.functions.registerValidators(*register_call_args).transact() diff --git a/src/validators/tasks.py b/src/validators/tasks.py index 2dcb99e1..6407579b 100644 --- a/src/validators/tasks.py +++ b/src/validators/tasks.py @@ -1,5 +1,6 @@ import logging +from sw_utils.typings import Bytes32 from web3 import Web3 from web3.types import BlockNumber, Wei @@ -70,7 +71,27 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) - ) return - oracles_approval = await get_oracles_approval(oracles, keystores, validators) + # get latest registry root + latest_registry_root = await validators_registry_contract.get_registry_root() + logger.debug('Fetched latest validators registry root: %s', latest_registry_root) + registry_root = None + + while True: + if not registry_root or registry_root != latest_registry_root: + registry_root = latest_registry_root + oracles_request = await get_oracles_request( + registry_root=registry_root, + oracles=oracles, + keystores=keystores, + validators=validators, + ) + + try: + oracles_approval = await get_oracles_approval(oracles=oracles, request=oracles_request) + break + except Exception as e: + logger.exception(e) + latest_registry_root = await validators_registry_contract.get_registry_root() if len(validators) == 1: validator = validators[0] @@ -79,30 +100,30 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) - validator=validator, approval=oracles_approval, update_state_call=update_state_call, + validators_registry_root=registry_root, ) logger.info('Successfully registered validator with public key %s', validator.public_key) if len(validators) > 1: await register_multiple_validator( - deposit_data.tree, validators, oracles_approval, update_state_call + tree=deposit_data.tree, + validators=validators, + approval=oracles_approval, + update_state_call=update_state_call, + validators_registry_root=registry_root, ) pub_keys = ', '.join([val.public_key for val in validators]) logger.info('Successfully registered validators with public keys %s', pub_keys) -async def get_oracles_approval( - oracles: Oracles, keystores: Keystores, validators: list[Validator] -) -> OraclesApproval: - """Fetches approval from oracles.""" - - # get latest registry root - registry_root = await validators_registry_contract.get_registry_root() - logger.debug('Fetched latest validators registry root: %s', registry_root) +async def get_oracles_request( + oracles: Oracles, keystores: Keystores, validators: list[Validator], registry_root: Bytes32 +) -> ApprovalRequest: + """Generate validator registration request data""" # get next validator index for exit signature latest_public_keys = await get_latest_network_validator_public_keys() validator_index = NetworkValidatorCrud().get_next_validator_index(list(latest_public_keys)) - start_validator_index = validator_index logger.debug('Next validator index for exit signature: %d', validator_index) # fetch current fork data @@ -118,6 +139,7 @@ async def get_oracles_approval( deposit_signatures=[], public_key_shards=[], exit_signature_shards=[], + proof=Bytes32(b''), ) for validator in validators: shards = get_exit_signature_shards( @@ -138,18 +160,21 @@ async def get_oracles_approval( request.exit_signature_shards.append(shards.exit_signatures) validator_index += 1 + return request + +async def get_oracles_approval(oracles: Oracles, request: ApprovalRequest) -> OraclesApproval: + """Fetches approval from oracles.""" # send approval request to oracles signatures, ipfs_hash = await send_approval_requests(oracles, request) logger.info( 'Fetched oracles approval for validators: count=%d, start index=%d', - len(validators), - start_validator_index, + len(request.public_keys), + request.validator_index, ) return OraclesApproval( signatures=signatures, ipfs_hash=ipfs_hash, - validators_registry_root=registry_root, ) diff --git a/src/validators/typings.py b/src/validators/typings.py index ed938c54..5fae6144 100644 --- a/src/validators/typings.py +++ b/src/validators/typings.py @@ -36,12 +36,12 @@ class ExitSignatureShards: @dataclass class OraclesApproval: - validators_registry_root: Bytes32 signatures: bytes ipfs_hash: str @dataclass +# pylint: disable-next=too-many-instance-attributes class ApprovalRequest: validator_index: int vault_address: ChecksumAddress @@ -50,6 +50,7 @@ class ApprovalRequest: deposit_signatures: list[HexStr] public_key_shards: list[list[HexStr]] exit_signature_shards: list[list[HexStr]] + proof: Bytes32 @dataclass diff --git a/src/validators/utils.py b/src/validators/utils.py index 20ac78de..c4e8aacb 100644 --- a/src/validators/utils.py +++ b/src/validators/utils.py @@ -73,7 +73,7 @@ async def send_approval_requests(oracles: Oracles, request: ApprovalRequest) -> raise RuntimeError('Not enough oracles to get approval from') if len(set(ipfs_hashes)) != 1: - raise ValueError('Different oracles IPFS hashes for approval request') + raise ValueError('Different oracles IPFS hashes for approval request.') signatures = b'' for address in sorted(responses.keys())[: oracles.validators_threshold]: