Skip to content

Commit 15babaa

Browse files
authored
Fix assertion on syncing. (#7315)
* Fix assertion on empty response processing. * Update AllTests.
1 parent 12ebba1 commit 15babaa

File tree

3 files changed

+102
-7
lines changed

3 files changed

+102
-7
lines changed

AllTests-mainnet.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,13 +976,15 @@ AllTests-mainnet
976976
+ [SyncManager] groupBlobs() test OK
977977
+ [SyncQueue# & Backward] Combination of missing parent and good blocks [3 peers] test OK
978978
+ [SyncQueue# & Backward] Empty responses should not advance queue until other peers will no OK
979+
+ [SyncQueue# & Backward] Empty responses should not be accounted [3 peers] test OK
979980
+ [SyncQueue# & Backward] Failure request push test OK
980981
+ [SyncQueue# & Backward] Invalid block [3 peers] test OK
981982
+ [SyncQueue# & Backward] Smoke [3 peers] test OK
982983
+ [SyncQueue# & Backward] Smoke [single peer] test OK
983984
+ [SyncQueue# & Backward] Unviable block [3 peers] test OK
984985
+ [SyncQueue# & Forward] Combination of missing parent and good blocks [3 peers] test OK
985986
+ [SyncQueue# & Forward] Empty responses should not advance queue until other peers will not OK
987+
+ [SyncQueue# & Forward] Empty responses should not be accounted [3 peers] test OK
986988
+ [SyncQueue# & Forward] Failure request push test OK
987989
+ [SyncQueue# & Forward] Invalid block [3 peers] test OK
988990
+ [SyncQueue# & Forward] Smoke [3 peers] test OK

beacon_chain/sync/sync_queue.nim

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@ type
3737
SyncQueueKind* {.pure.} = enum
3838
Forward, Backward
3939

40+
SyncRequestFlag* {.pure.} = enum
41+
Void
42+
4043
SyncRequest*[T] = object
4144
kind*: SyncQueueKind
4245
data*: SyncRange
46+
flags*: set[SyncRequestFlag]
4347
item*: T
4448

4549
SyncQueueItem[T] = object
@@ -472,11 +476,11 @@ func init*[T](t1: typedesc[SyncQueue], t2: typedesc[T],
472476
ident: ident
473477
)
474478

475-
func contains[T](requests: openArray[SyncRequest[T]], source: T): bool =
476-
for req in requests:
477-
if req.item == source:
478-
return true
479-
false
479+
func searchPeer[T](requests: openArray[SyncRequest[T]], source: T): int =
480+
for index, request in requests.pairs():
481+
if request.item == source:
482+
return index
483+
-1
480484

481485
func find[T](sq: SyncQueue[T], req: SyncRequest[T]): Opt[SyncPosition] =
482486
if len(sq.requests) == 0:
@@ -539,7 +543,8 @@ proc pop*[T](sq: SyncQueue[T], peerMaxSlot: Slot, item: T): SyncRequest[T] =
539543
var count = 0
540544
for qitem in sq.requests.mitems():
541545
if len(qitem.requests) < sq.requestsCount:
542-
if item notin qitem.requests:
546+
let sindex = qitem.requests.searchPeer(item)
547+
if sindex < 0:
543548
return
544549
if qitem.data.slot > peerMaxSlot:
545550
# Peer could not satisfy our request, returning empty one.
@@ -551,7 +556,9 @@ proc pop*[T](sq: SyncQueue[T], peerMaxSlot: Slot, item: T): SyncRequest[T] =
551556
qitem.requests.add(request)
552557
request
553558
else:
554-
inc(count)
559+
if SyncRequestFlag.Void notin qitem.requests[sindex].flags:
560+
# We only count non-empty requests.
561+
inc(count)
555562

556563
doAssert(count < sq.requestsCount,
557564
"You should not pop so many requests for single peer")
@@ -835,6 +842,10 @@ proc push*[T](
835842

836843
sr.item.updateStats(SyncResponseKind.Empty, 1'u64)
837844
inc(sq.requests[position.qindex].voidsCount)
845+
# Mark empty request in queue, so this range will not be requested by
846+
# the same peer.
847+
sq.requests[position.qindex].requests[position.sindex].flags.incl(
848+
SyncRequestFlag.Void)
838849
sq.gapList.add(GapItem.init(sr))
839850
# With empty response - advance only when `requestsCount` of different
840851
# peers returns empty response for the same range.

tests/test_sync_manager.nim

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,88 @@ suite "SyncManager test suite":
855855
sq.inpSlot == finishSlot
856856
sq.outSlot == finishSlot
857857

858+
asyncTest "[SyncQueue# & " & $kind & "] Empty responses should not " &
859+
"be accounted [3 peers] test":
860+
var emptyResponse: seq[ref ForkedSignedBeaconBlock]
861+
let
862+
scenario =
863+
case kind
864+
of SyncQueueKind.Forward:
865+
[
866+
(Slot(0) .. Slot(31), Opt.none(VerifierError)),
867+
(Slot(32) .. Slot(63), Opt.none(VerifierError)),
868+
(Slot(64) .. Slot(95), Opt.none(VerifierError)),
869+
(Slot(96) .. Slot(127), Opt.none(VerifierError)),
870+
(Slot(128) .. Slot(159), Opt.none(VerifierError))
871+
]
872+
of SyncQueueKind.Backward:
873+
[
874+
(Slot(128) .. Slot(159), Opt.none(VerifierError)),
875+
(Slot(96) .. Slot(127), Opt.none(VerifierError)),
876+
(Slot(64) .. Slot(95), Opt.none(VerifierError)),
877+
(Slot(32) .. Slot(63), Opt.none(VerifierError)),
878+
(Slot(0) .. Slot(31), Opt.none(VerifierError))
879+
]
880+
verifier = setupVerifier(kind, scenario)
881+
sq =
882+
case kind
883+
of SyncQueueKind.Forward:
884+
SyncQueue.init(SomeTPeer, kind, Slot(0), Slot(159),
885+
32'u64, # 32 slots per request
886+
3, # 3 concurrent requests
887+
2, # 2 failures allowed
888+
getStaticSlotCb(Slot(0)),
889+
verifier.collector)
890+
of SyncQueueKind.Backward:
891+
SyncQueue.init(SomeTPeer, kind, Slot(159), Slot(0),
892+
32'u64, # 32 slots per request
893+
3, # 3 concurrent requests
894+
2, # 2 failures allowed
895+
getStaticSlotCb(Slot(159)),
896+
verifier.collector)
897+
slots =
898+
case kind
899+
of SyncQueueKind.Forward:
900+
@[Slot(0), Slot(32), Slot(64), Slot(96), Slot(128)]
901+
of SyncQueueKind.Backward:
902+
@[Slot(128), Slot(96), Slot(64), Slot(32), Slot(0)]
903+
peer1 = SomeTPeer.init("1")
904+
peer2 = SomeTPeer.init("2")
905+
peer3 = SomeTPeer.init("3")
906+
907+
let
908+
r11 = sq.pop(Slot(159), peer1)
909+
r21 = sq.pop(Slot(159), peer2)
910+
await sq.push(r11, emptyResponse, Opt.none(seq[BlobSidecars]))
911+
let
912+
r12 = sq.pop(Slot(159), peer1)
913+
r13 = sq.pop(Slot(159), peer1)
914+
# This should not raise an assertion, as the previously sent empty
915+
# response should not be taken into account.
916+
r14 = sq.pop(Slot(159), peer1)
917+
918+
expect AssertionError:
919+
let r1e {.used.} = sq.pop(Slot(159), peer1)
920+
921+
check:
922+
r11.data.slot == slots[0]
923+
r12.data.slot == slots[1]
924+
r13.data.slot == slots[2]
925+
r14.data.slot == slots[3]
926+
927+
# Scenario requires some finish steps
928+
await sq.push(r21, createChain(r21.data), Opt.none(seq[BlobSidecars]))
929+
let r22 = sq.pop(Slot(159), peer2)
930+
await sq.push(r22, createChain(r22.data), Opt.none(seq[BlobSidecars]))
931+
let r23 = sq.pop(Slot(159), peer2)
932+
await sq.push(r23, createChain(r23.data), Opt.none(seq[BlobSidecars]))
933+
let r24 = sq.pop(Slot(159), peer2)
934+
await sq.push(r24, createChain(r24.data), Opt.none(seq[BlobSidecars]))
935+
let r35 = sq.pop(Slot(159), peer3)
936+
await sq.push(r35, createChain(r35.data), Opt.none(seq[BlobSidecars]))
937+
938+
await noCancel wait(verifier.verifier, 2.seconds)
939+
858940
asyncTest "[SyncQueue# & " & $kind & "] Combination of missing parent " &
859941
"and good blocks [3 peers] test":
860942
let

0 commit comments

Comments
 (0)