diff --git a/.env.example b/.env.example index 092b299..9f94f44 100644 --- a/.env.example +++ b/.env.example @@ -13,5 +13,9 @@ CONSENSUS_ENDPOINT=https://hoodi-lighthouse PUBLIC_KEYS_FILE=public_keys.csv +# Validators manager VALIDATORS_MANAGER_KEY_FILE=validators-manager-key.json VALIDATORS_MANAGER_PASSWORD_FILE=validators-manager-password.txt + +# Maximum number of parallel event scan queries +# EVENT_LOGS_MAX_CONCURRENCY=4 diff --git a/src/common/contracts.py b/src/common/contracts.py index 0895953..170b4a6 100644 --- a/src/common/contracts.py +++ b/src/common/contracts.py @@ -1,3 +1,5 @@ +import asyncio +import itertools import json import os from functools import cached_property @@ -50,15 +52,28 @@ async def _get_last_event( ) -> EventData | None: blocks_range = self.events_blocks_range_interval - while to_block >= from_block: - events = await event.get_logs( - from_block=BlockNumber(max(to_block - blocks_range, from_block)), - to_block=to_block, + # Build all chunk ranges from newest to oldest + ranges: list[tuple[BlockNumber, BlockNumber]] = [] + chunk_to = to_block + while chunk_to >= from_block: + chunk_from = BlockNumber(max(chunk_to - blocks_range + 1, from_block)) + ranges.append((chunk_from, chunk_to)) + chunk_to = BlockNumber(chunk_to - blocks_range) + + # from_block and to_block are both inclusive + async def fetch_chunk(chunk_from: BlockNumber, chunk_to: BlockNumber) -> list[EventData]: + return await event.get_logs( + from_block=chunk_from, + to_block=chunk_to, argument_filters=argument_filters, ) - if events: - return events[-1] - to_block = BlockNumber(to_block - blocks_range - 1) + + # Process chunks in batches (newest-first), abort on first hit + for batch in itertools.batched(ranges, settings.event_logs_max_concurrency): + batch_results = await asyncio.gather(*[fetch_chunk(f, t) for f, t in batch]) + for chunk_events in batch_results: + if chunk_events: + return chunk_events[-1] return None diff --git a/src/config/settings.py b/src/config/settings.py index 10a6855..7d1e626 100644 --- a/src/config/settings.py +++ b/src/config/settings.py @@ -45,6 +45,8 @@ validator_lifetime: int = config('VALIDATOR_LIFETIME', default=3600, cast=int) +event_logs_max_concurrency: int = config('EVENT_LOGS_MAX_CONCURRENCY', default=4, cast=int) + validators_manager_key_file: str = config('VALIDATORS_MANAGER_KEY_FILE') validators_manager_password_file: str = config('VALIDATORS_MANAGER_PASSWORD_FILE')