Skip to content

Commit 65bba2a

Browse files
authored
Improve quarantine performance on forked chains (#7006)
* Improve quarantine performance on forked chains A bit silly, but if we downloaded an orphan, we'd keep re-downloading it if the missing list was full. Also, we'd keep redownloading unviables :/ * lint
1 parent 742cd83 commit 65bba2a

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

AllTests-mainnet.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ AllTests-mainnet
124124
```
125125
## Block quarantine
126126
```diff
127+
+ Don't re-download unviable blocks OK
128+
+ Keep downloading parent chain even if we hit missing limit OK
127129
+ Recursive missing parent OK
128130
+ Unviable smoke test OK
129131
```

beacon_chain/consensus_object_pools/block_quarantine.nim

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# beacon_chain
2-
# Copyright (c) 2018-2024 Status Research & Development GmbH
2+
# Copyright (c) 2018-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -18,7 +18,7 @@ export tables, forks
1818
const
1919
MaxRetriesPerMissingItem = 7
2020
## Exponential backoff, double interval between each attempt
21-
MaxMissingItems = 1024
21+
MaxMissingItems* = 1024
2222
## Arbitrary
2323
MaxOrphans = SLOTS_PER_EPOCH * 3
2424
## Enough for finalization in an alternative fork
@@ -215,6 +215,9 @@ func removeUnviableBloblessTree(
215215
toRemove.setLen(0)
216216

217217
func addUnviable*(quarantine: var Quarantine, root: Eth2Digest) =
218+
# Unviable - don't try to download again!
219+
quarantine.missing.del(root)
220+
218221
if root in quarantine.unviable:
219222
return
220223

@@ -281,18 +284,24 @@ func addOrphan*(
281284
quarantine: var Quarantine, finalizedSlot: Slot,
282285
signedBlock: ForkedSignedBeaconBlock): Result[void, cstring] =
283286
## Adds block to quarantine's `orphans` and `missing` lists.
287+
284288
if not isViable(finalizedSlot, getForkedBlockField(signedBlock, slot)):
285-
quarantine.addUnviable(signedBlock.root)
289+
quarantine.addUnviable(signedBlock.root) # will remove from missing
286290
return err("block unviable")
287291

288292
quarantine.cleanupOrphans(finalizedSlot)
289293

290294
let parent_root = getForkedBlockField(signedBlock, parent_root)
291295

292296
if parent_root in quarantine.unviable:
293-
quarantine.unviable[signedBlock.root] = ()
297+
quarantine.addUnviable(signedBlock.root)
294298
return err("block parent unviable")
295299

300+
# It's no longer missing if we downloaded it - remove before adding to make
301+
# sure parent chains get downloaded even if missing list is full (works as
302+
# long as the orphan was in the missing list, which is likely)
303+
quarantine.missing.del(signedBlock.root)
304+
296305
# Even if the quarantine is full, we need to schedule its parent for
297306
# downloading or we'll never get to the bottom of things
298307
quarantine.addMissing(parent_root)
@@ -307,7 +316,6 @@ func addOrphan*(
307316
quarantine.blobless.del oldest_orphan_key[0]
308317

309318
quarantine.orphans[(signedBlock.root, signedBlock.signature)] = signedBlock
310-
quarantine.missing.del(signedBlock.root)
311319

312320
ok()
313321

tests/test_block_quarantine.nim

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# beacon_chain
2-
# Copyright (c) 2022-2024 Status Research & Development GmbH
2+
# Copyright (c) 2022-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -10,6 +10,7 @@
1010

1111
import
1212
unittest2,
13+
chronicles,
1314
../beacon_chain/spec/forks,
1415
../beacon_chain/spec/datatypes/[phase0, deneb],
1516
../beacon_chain/consensus_object_pools/block_quarantine
@@ -118,3 +119,39 @@ suite "Block quarantine":
118119
b0.root in quarantine.missing
119120
b1.root notin quarantine.missing
120121
b2.root notin quarantine.missing
122+
123+
test "Keep downloading parent chain even if we hit missing limit":
124+
var quarantine: Quarantine
125+
var blocks = @[makeBlock(Slot 0, ZERO_HASH)]
126+
for i in 0..<MaxMissingItems:
127+
blocks.add makeBlock(blocks[^1].slot + 1, blocks[^1].root)
128+
129+
# Fill missing list with junk
130+
for i in 0..<MaxMissingItems:
131+
quarantine.addMissing(blocks[^(i + 1)].root)
132+
133+
check:
134+
blocks[0].root notin quarantine.missing
135+
quarantine.addOrphan(Slot 0, blocks[1]) == Result[void, cstring].ok()
136+
blocks[0].root in quarantine.missing
137+
138+
test "Don't re-download unviable blocks":
139+
var quarantine: Quarantine
140+
let
141+
b0 = makeBlock(Slot 0, ZERO_HASH)
142+
b1 = makeBlock(Slot 1, b0.root)
143+
b2 = makeBlock(Slot 2, b1.root)
144+
145+
quarantine.addMissing(b1.root)
146+
quarantine.addMissing(b2.root)
147+
148+
check:
149+
b2.root in quarantine.missing
150+
151+
quarantine.addUnviable(b1.root)
152+
check:
153+
b1.root notin quarantine.missing
154+
155+
check:
156+
quarantine.addOrphan(Slot 0, b2).isErr()
157+
b2.root notin quarantine.missing

0 commit comments

Comments
 (0)