@@ -364,13 +364,17 @@ def run_sync_blocks(self) -> Generator[Any, Any, None]:
364
364
# Get my best block.
365
365
my_best_block = self .get_my_best_block ()
366
366
367
- # Find peer's best block
367
+ # Get peer's best block
368
368
self .peer_best_block = yield self .get_peer_best_block ()
369
369
assert self .peer_best_block is not None
370
370
371
- # find best common block
371
+ # Find best common block
372
372
self .synced_block = yield self .find_best_common_block (my_best_block , self .peer_best_block )
373
- assert self .synced_block is not None
373
+ if self .synced_block is None :
374
+ # Find best common block failed. Try again soon.
375
+ # This might happen if a reorg occurs during the search.
376
+ return
377
+
374
378
self .log .debug ('run_sync_blocks' ,
375
379
my_best_block = my_best_block ,
376
380
peer_best_block = self .peer_best_block ,
@@ -516,7 +520,7 @@ def partial_vertex_exists(self, vertex_id: VertexId) -> bool:
516
520
@inlineCallbacks
517
521
def find_best_common_block (self ,
518
522
my_best_block : _HeightInfo ,
519
- peer_best_block : _HeightInfo ) -> Generator [Any , Any , _HeightInfo ]:
523
+ peer_best_block : _HeightInfo ) -> Generator [Any , Any , Optional [ _HeightInfo ] ]:
520
524
""" Search for the highest block/height where we're synced.
521
525
"""
522
526
self .log .debug ('find_best_common_block' , peer_best_block = peer_best_block , my_best_block = my_best_block )
@@ -545,36 +549,49 @@ def find_best_common_block(self,
545
549
# Run an n-ary search in the interval [lo, hi).
546
550
# `lo` is always a height where we are synced.
547
551
# `hi` is always a height where sync state is unknown.
548
- hi = min (peer_best_block .height , my_best_block .height )
549
- lo = 0
550
-
551
- lo_block_hash = self ._settings .GENESIS_BLOCK_HASH
552
+ hi = min (peer_best_block , my_best_block , key = lambda x : x .height )
553
+ lo = _HeightInfo (height = 0 , id = self ._settings .GENESIS_BLOCK_HASH )
552
554
553
- while hi - lo > 1 :
555
+ while hi . height - lo . height > 1 :
554
556
self .log .info ('find_best_common_block n-ary search query' , lo = lo , hi = hi )
555
- step = math .ceil ((hi - lo ) / 10 )
556
- heights = list (range (lo , hi , step ))
557
- heights .append (hi )
558
-
559
- block_height_list = yield self .get_peer_block_hashes (heights )
560
- block_height_list .sort (key = lambda x : x .height , reverse = True )
561
-
562
- for height , block_hash in block_height_list :
557
+ step = math .ceil ((hi .height - lo .height ) / 10 )
558
+ heights = list (range (lo .height , hi .height , step ))
559
+ heights .append (hi .height )
560
+
561
+ block_info_list = yield self .get_peer_block_hashes (heights )
562
+ block_info_list .sort (key = lambda x : x .height , reverse = True )
563
+
564
+ # As we are supposed to be always synced at `lo`, we expect to receive a response
565
+ # with at least one item equals to lo. If it does not happen, we stop the search
566
+ # and return None. This might be caused when a reorg occurs during the search.
567
+ if not block_info_list :
568
+ self .log .info ('n-ary search failed because it got a response with no lo_block_info' ,
569
+ lo = lo ,
570
+ hi = hi )
571
+ return None
572
+ lo_block_info = block_info_list [- 1 ]
573
+ if lo_block_info != lo :
574
+ self .log .info ('n-ary search failed because lo != lo_block_info' ,
575
+ lo = lo ,
576
+ hi = hi ,
577
+ lo_block_info = lo_block_info )
578
+ return None
579
+
580
+ for info in block_info_list :
563
581
try :
564
582
# We must check only fully validated transactions.
565
- blk = self .tx_storage .get_transaction (block_hash )
583
+ blk = self .tx_storage .get_transaction (info . id )
566
584
except TransactionDoesNotExist :
567
- hi = height
585
+ hi = info
568
586
else :
569
587
assert blk .get_metadata ().validation .is_fully_connected ()
570
588
assert isinstance (blk , Block )
571
- assert height == blk .get_height ()
572
- lo = height
573
- lo_block_hash = block_hash
589
+ assert info .height == blk .get_height ()
590
+ lo = info
574
591
break
575
592
576
593
self .log .debug ('find_best_common_block n-ary search finished' , lo = lo , hi = hi )
577
- return _HeightInfo ( height = lo , id = lo_block_hash )
594
+ return lo
578
595
579
596
def get_peer_block_hashes (self , heights : list [int ]) -> Deferred [list [_HeightInfo ]]:
580
597
""" Returns the peer's block hashes in the given heights.
0 commit comments