2020)
2121from dipdup .context import DipDupContext
2222from dipdup .datasources .tzkt .datasource import BigMapFetcher , OperationFetcher , TzktDatasource
23- from dipdup .exceptions import InvalidDataError
23+ from dipdup .exceptions import ConfigInitializationException , InvalidDataError
2424from dipdup .models import BigMapData , BigMapDiff , HeadBlockData
2525from dipdup .models import Index as IndexState
2626from dipdup .models import IndexStatus , OperationData , Origination , Transaction
@@ -86,7 +86,11 @@ async def process(self) -> None:
8686
8787 elif self ._datasource .sync_level is None :
8888 self ._logger .info ('Datasource is not active, sync to the latest block' )
89- last_level = (await self ._datasource .get_head_block ()).level
89+ # NOTE: Late establishing connection to the WebSocket
90+ if self .datasource .head :
91+ last_level = self .datasource .head .level
92+ else :
93+ last_level = (await self ._datasource .get_head_block ()).level
9094 await self ._synchronize (last_level )
9195
9296 elif self ._datasource .sync_level > self .state .level :
@@ -154,6 +158,7 @@ async def single_level_rollback(self, from_level: int) -> None:
154158 raise RuntimeError ('Index level is higher than rollback level' )
155159
156160 async def _process_queue (self ) -> None :
161+ """Process WebSocket queue"""
157162 if not self ._queue :
158163 return
159164 self ._logger .info ('Processing websocket queue' )
@@ -195,8 +200,8 @@ async def _synchronize(self, last_level: int, cache: bool = False) -> None:
195200 await self ._exit_sync_state (last_level )
196201
197202 async def _process_level_operations (self , level : int , operations : List [OperationData ], block : Optional [HeadBlockData ] = None ) -> None :
198- if level < self .state .level :
199- raise RuntimeError (f'Level of operation batch is lower than index state level: { level } < { self .state .level } ' )
203+ if level <= self .state .level :
204+ raise RuntimeError (f'Level of operation batch must be higher than index state level: { level } <= { self .state .level } ' )
200205
201206 if self ._rollback_level :
202207 levels = {
@@ -214,7 +219,7 @@ async def _process_level_operations(self, level: int, operations: List[Operation
214219 received_hashes = set ([op .hash for op in operations ])
215220 reused_hashes = received_hashes & expected_hashes
216221 if reused_hashes != expected_hashes :
217- await self ._ctx .reindex (reason = 'attempted a single level rollback, but arrived block differs from processed one ' )
222+ await self ._ctx .reindex (reason = 'attempted a single level rollback, but arrived block has additional transactions ' )
218223
219224 self ._rollback_level = None
220225 self ._last_hashes = set ()
@@ -324,7 +329,7 @@ async def _on_match(
324329 """Prepare handler arguments, parse parameter and storage. Schedule callback in executor."""
325330 self ._logger .info ('%s: `%s` handler matched!' , operation_subgroup .hash , handler_config .callback )
326331 if not handler_config .parent :
327- raise RuntimeError ( 'Handler must have a parent' )
332+ raise ConfigInitializationException
328333
329334 args : List [Optional [Union [Transaction , Origination , OperationData ]]] = []
330335 for pattern_config , operation in zip (handler_config .pattern , matched_operations ):
@@ -415,7 +420,8 @@ def __init__(self, ctx: DipDupContext, config: BigMapIndexConfig, datasource: Tz
415420 def push (self , level : int , big_maps : List [BigMapData ], block : Optional [HeadBlockData ] = None ):
416421 self ._queue .append ((level , big_maps , block ))
417422
418- async def _process_queue (self ):
423+ async def _process_queue (self ) -> None :
424+ """Process WebSocket queue"""
419425 if not self ._queue :
420426 return
421427 self ._logger .info ('Processing websocket queue' )
@@ -450,8 +456,8 @@ async def _synchronize(self, last_level: int, cache: bool = False) -> None:
450456 await self ._exit_sync_state (last_level )
451457
452458 async def _process_level_big_maps (self , level : int , big_maps : List [BigMapData ], block : Optional [HeadBlockData ] = None ):
453- if level < self .state .level :
454- raise RuntimeError (f'Level of operation batch is lower than index state level: { level } < { self .state .level } ' )
459+ if level <= self .state .level :
460+ raise RuntimeError (f'Level of big map batch must be higher than index state level: { level } <= { self .state .level } ' )
455461
456462 async with in_global_transaction ():
457463 self ._logger .info ('Processing %s big map diffs of level %s' , len (big_maps ), level )
@@ -479,7 +485,7 @@ async def _on_match(
479485 """Prepare handler arguments, parse key and value. Schedule callback in executor."""
480486 self ._logger .info ('%s: `%s` handler matched!' , matched_big_map .operation_id , handler_config .callback )
481487 if not handler_config .parent :
482- raise RuntimeError ( 'Handler must have a parent' )
488+ raise ConfigInitializationException
483489
484490 if matched_big_map .action .has_key :
485491 key_type = handler_config .key_type_cls
@@ -525,14 +531,14 @@ async def _process_big_maps(self, big_maps: List[BigMapData]) -> None:
525531 await self ._on_match (handler_config , big_map )
526532
527533 async def _get_big_map_addresses (self ) -> Set [str ]:
528- """Get addresses to fetch transactions from during initial synchronization"""
534+ """Get addresses to fetch big map diffs from during initial synchronization"""
529535 addresses = set ()
530536 for handler_config in self ._config .handlers :
531537 addresses .add (cast (ContractConfig , handler_config .contract ).address )
532538 return addresses
533539
534540 async def _get_big_map_paths (self ) -> Set [str ]:
535- """Get addresses to fetch transactions from during initial synchronization"""
541+ """Get addresses to fetch big map diffs from during initial synchronization"""
536542 paths = set ()
537543 for handler_config in self ._config .handlers :
538544 paths .add (handler_config .path )
0 commit comments