Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 11 additions & 42 deletions beacon_chain/consensus_object_pools/blob_quarantine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -484,15 +484,7 @@ func hasSidecars*[A: SomeDataColumnSidecar, B: OnDataColumnSidecarCallback](
if isNil(node):
return false

let
supernode = (len(quarantine.custodyColumns) == NUMBER_OF_COLUMNS)
columnsCount =
if supernode:
(NUMBER_OF_COLUMNS div 2 + 1)
else:
len(quarantine.custodyColumns)

if node[].value.count < columnsCount:
if node[].value.count < len(quarantine.custodyColumns):
# Quarantine does not hold enough column sidecars.
return false
true
Expand Down Expand Up @@ -579,13 +571,8 @@ proc popSidecars*[A: SomeDataColumnSidecar, B: OnDataColumnSidecarCallback](

let
supernode = (len(quarantine.custodyColumns) == NUMBER_OF_COLUMNS)
columnsCount =
if supernode:
(NUMBER_OF_COLUMNS div 2 + 1)
else:
len(quarantine.custodyColumns)

if node[].value.count < columnsCount:
if node[].value.count < len(quarantine.custodyColumns):
# Quarantine does not hold enough column sidecars.
return Opt.none(seq[ref A])

Expand All @@ -597,18 +584,11 @@ proc popSidecars*[A: SomeDataColumnSidecar, B: OnDataColumnSidecarCallback](
var sidecars: seq[ref A]
if supernode:
for sidecar in node[].value.sidecars:
# Supernode could have some of the columns not filled.
if not(sidecar.isEmpty()):
doAssert(sidecar.isLoaded(),
"Record should only have loaded values, but it is `" &
doAssert(not(sidecar.isEmpty()), "Record should not have empty values")
doAssert(sidecar.isLoaded(),
"Record should only have loaded values, but it is `" &
$sidecar.kind & "`")
sidecars.add(sidecar.data)
if len(sidecars) >= (NUMBER_OF_COLUMNS div 2 + 1):
break

doAssert(len(sidecars) >= (NUMBER_OF_COLUMNS div 2 + 1),
"Incorrect amount of sidecars in record for supernode - " &
$len(sidecars))
sidecars.add(sidecar.data)
else:
for cindex in quarantine.custodyColumns:
let index = quarantine.getIndex(cindex)
Expand Down Expand Up @@ -703,33 +683,22 @@ func fetchMissingSidecars*[A: SomeDataColumnSidecar, B: OnDataColumnSidecarCallb

let
supernode = (len(quarantine.custodyColumns) == NUMBER_OF_COLUMNS)
columnsCount =
if supernode:
(NUMBER_OF_COLUMNS div 2)
else:
len(quarantine.custodyColumns)

if supernode:
if isNil(node):
# We do not have any columns yet, so we push all columns peer could
# provide.
for column in peerMap.items():
if len(res) > columnsCount:
# We don't need to request more than (NUMBER_OF_COLUMNS div 2)
# columns.
break
res.incl(column)
else:
if node[].value.count > columnsCount:
# We already have enough columns for reconstruction.
if node[].value.count == len(quarantine.custodyColumns):
# We already have all columns.
return
DataColumnsByRootIdentifier(
block_root: blockRoot,
indices: DataColumnIndices(default(seq[ColumnIndex])))

for column in peerMap.items():
if node[].value.count + len(res) > columnsCount:
# We don't need to request more than (NUMBER_OF_COLUMNS div 2)
# columns.
break
let index = quarantine.getIndex(column)
if (index == -1) or node[].value.sidecars[index].isEmpty():
res.incl(column)
Expand Down Expand Up @@ -770,7 +739,7 @@ func getMissingColumnsMap*[A: SomeDataColumnSidecar, B: OnDataColumnSidecarCallb
for index in 0 ..< NUMBER_OF_COLUMNS:
res.incl(ColumnIndex(index))
else:
if len(node[].value.sidecars) > NUMBER_OF_COLUMNS div 2:
if node[].value.count >= NUMBER_OF_COLUMNS:
return res
for index in 0 ..< NUMBER_OF_COLUMNS:
if node[].value.sidecars[index].isEmpty():
Expand Down
5 changes: 1 addition & 4 deletions beacon_chain/el/el_getblobs_service.nim
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,13 @@ proc attemptGetBlobs*(
flat_proof)
# Send notification to event stream
# and add these columns to column quarantine
const MaxColsPerPut = (NUMBER_OF_COLUMNS div 2) + 1
var batch =
newSeqOfCap[ref fulu.DataColumnSidecar](MaxColsPerPut)
newSeqOfCap[ref fulu.DataColumnSidecar](NUMBER_OF_COLUMNS)

for col in recovered_columns:
if col.index notin self.dataColumnQuarantine[].custodyColumns:
continue
batch.add newClone(col)
if batch.len == MaxColsPerPut:
break

if batch.len > 0:
debug "Added data columns from EL blobpool to quarantine",
Expand Down
2 changes: 1 addition & 1 deletion beacon_chain/spec/column_map.nim
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,6 @@ func `$`*(a: ColumnMap): string =
"[" & a.items().toSeq().mapIt($it).join(", ") & "]"

func shortLog*(a: ColumnMap): string =
if len(a) > NUMBER_OF_COLUMNS div 2:
if len(a) == NUMBER_OF_COLUMNS:
return "[supernode]"
$a
6 changes: 3 additions & 3 deletions tests/test_column_map.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# beacon_chain
# Copyright (c) 2025 Status Research & Development GmbH
# Copyright (c) 2025-2026 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
Expand Down Expand Up @@ -103,9 +103,9 @@ suite "ColumnMap test suite":
vector[2]

test "supernode test":
for max in ((NUMBER_OF_COLUMNS div 2) + 1) ..< NUMBER_OF_COLUMNS:
block:
var columns: seq[ColumnIndex]
for i in 0 ..< max:
for i in 0 ..< NUMBER_OF_COLUMNS:
columns.add(ColumnIndex(i))
let map = ColumnMap.init(columns)
check:
Expand Down
93 changes: 37 additions & 56 deletions tests/test_quarantine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1394,14 +1394,14 @@ suite "ColumnQuarantine data structure test suite " & preset():
sidecars1 =
block:
var res: seq[ref fulu.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genFuluDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1, proposer_index = 5)))
res
sidecars2 =
block:
var res: seq[ref fulu.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genFuluDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1, proposer_index = 6)))
res
Expand Down Expand Up @@ -1564,14 +1564,14 @@ suite "ColumnQuarantine data structure test suite " & preset():
sidecars1 =
block:
var res: seq[ref fulu.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genFuluDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1, proposer_index = 5)))
res
sidecars2 =
block:
var res: seq[ref fulu.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genFuluDataColumnSidecar(
index = int(custodyColumns[i]), slot = 2, proposer_index = 50)))
res
Expand All @@ -1582,18 +1582,16 @@ suite "ColumnQuarantine data structure test suite " & preset():
missing: DataColumnsByRootIdentifier
): bool =
const ExpectedVectors = [
(@[63, 64, 65, 66, 95, 96, 97, 98], 0 .. 57),
(@[63, 64, 65, 66, 95, 96, 97], 58 .. 58),
(@[63, 64, 65, 66, 95, 96], 59 .. 59),
(@[63, 64, 65, 66, 95], 60 .. 60),
(@[63, 64, 65, 66], 61 .. 61),
(@[63, 64, 65], 62 .. 62),
(@[63, 64], 63 .. 63),
(@[64], 64 .. 64),
(@[], 65 .. 65)
(@[63, 64, 65, 66, 95, 96, 97, 98], 0 .. 63),
(@[64, 65, 66, 95, 96, 97, 98], 64 .. 64),
(@[65, 66, 95, 96, 97, 98], 65 .. 65),
(@[66, 95, 96, 97, 98], 66 .. 66),
(@[95, 96, 97, 98], 67 .. 95),
(@[96, 97, 98], 96 .. 96),
(@[97, 98], 97 .. 97),
(@[98], 98 .. 98),
(@[], 99 .. 127)
]

doAssert(index in 0 .. 65)
for expect in ExpectedVectors:
if index in expect[1]:
if len(expect[0]) != len(missing.indices):
Expand All @@ -1606,7 +1604,7 @@ suite "ColumnQuarantine data structure test suite " & preset():
return true
false

for i in 0 ..< len(sidecars1) + 1:
for i in 0 ..< len(sidecars1):
let
missing1 = bq.fetchMissingSidecars(broot1)
missing2 = bq.fetchMissingSidecars(broot2)
Expand All @@ -1619,12 +1617,7 @@ suite "ColumnQuarantine data structure test suite " & preset():
compareSidecars(
broot2,
sidecars2.toOpenArray(i, len(sidecars2) - 1), missing2) == true
checkSupernodeExpected(
broot1,
i, missing3) == true

if i >= len(sidecars1):
break
checkSupernodeExpected(broot1, i, missing3) == true

bq.put(broot1, sidecars1[i])
bq.put(broot2, sidecars2[i])
Expand Down Expand Up @@ -2571,12 +2564,9 @@ suite "ColumnQuarantine data structure test suite " & preset():
finish = len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
of "supernode":
# In case of super node quarantine returns
# NUMBER_OF_COLUMNS div 2 + 1 columns which is enough for
# rebuild.
let
start = 0
finish = len(custodyColumns) div 2 + 1
finish = len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
else:
raiseAssert "inaccessible"
Expand All @@ -2588,12 +2578,9 @@ suite "ColumnQuarantine data structure test suite " & preset():
finish = start + len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
of "supernode":
# In case of super node quarantine returns
# NUMBER_OF_COLUMNS div 2 + 1 columns which is enough for
# rebuild.
let
start = len(custodyColumns)
finish = start + len(custodyColumns) div 2 + 1
finish = start + len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
else:
raiseAssert "inaccessible"
Expand Down Expand Up @@ -3092,14 +3079,14 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
sidecars1 =
block:
var res: seq[ref gloas.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genGloasDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1)))
res
sidecars2 =
block:
var res: seq[ref gloas.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genGloasDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1)))
res
Expand Down Expand Up @@ -3262,14 +3249,14 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
sidecars1 =
block:
var res: seq[ref gloas.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genGloasDataColumnSidecar(
index = int(custodyColumns[i]), slot = 1)))
res
sidecars2 =
block:
var res: seq[ref gloas.DataColumnSidecar]
for i in 0 ..< (len(custodyColumns) div 2 + 1):
for i in 0 ..< len(custodyColumns):
res.add(newClone(genGloasDataColumnSidecar(
index = int(custodyColumns[i]), slot = 2)))
res
Expand All @@ -3280,18 +3267,17 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
missing: DataColumnsByRootIdentifier
): bool =
const ExpectedVectors = [
(@[63, 64, 65, 66, 95, 96, 97, 98], 0 .. 57),
(@[63, 64, 65, 66, 95, 96, 97], 58 .. 58),
(@[63, 64, 65, 66, 95, 96], 59 .. 59),
(@[63, 64, 65, 66, 95], 60 .. 60),
(@[63, 64, 65, 66], 61 .. 61),
(@[63, 64, 65], 62 .. 62),
(@[63, 64], 63 .. 63),
(@[64], 64 .. 64),
(@[], 65 .. 65)
(@[63, 64, 65, 66, 95, 96, 97, 98], 0 .. 63),
(@[64, 65, 66, 95, 96, 97, 98], 64 .. 64),
(@[65, 66, 95, 96, 97, 98], 65 .. 65),
(@[66, 95, 96, 97, 98], 66 .. 66),
(@[95, 96, 97, 98], 67 .. 95),
(@[96, 97, 98], 96 .. 96),
(@[97, 98], 97 .. 97),
(@[98], 98 .. 98),
(@[], 99 .. 127)
]

doAssert(index in 0 .. 65)
for expect in ExpectedVectors:
if index in expect[1]:
if len(expect[0]) != len(missing.indices):
Expand All @@ -3304,7 +3290,7 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
return true
false

for i in 0 ..< len(sidecars1) + 1:
for i in 0 ..< len(sidecars1):
let
missing1 = bq.fetchMissingSidecars(broot1)
missing2 = bq.fetchMissingSidecars(broot2)
Expand All @@ -3321,9 +3307,6 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
broot1,
i, missing3) == true

if i >= len(sidecars1):
break

bq.put(broot1, sidecars1[i])
bq.put(broot2, sidecars2[i])

Expand Down Expand Up @@ -4230,12 +4213,11 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
finish = len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
of "supernode":
# In case of super node quarantine returns
# NUMBER_OF_COLUMNS div 2 + 1 columns which is enough for
# rebuild.
# In case of super node quarantine returns all
# NUMBER_OF_COLUMNS columns.
let
start = 0
finish = len(custodyColumns) div 2 + 1
finish = len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
else:
raiseAssert "inaccessible"
Expand All @@ -4247,12 +4229,11 @@ suite "GloasColumnQuarantine data structure test suite " & preset():
finish = start + len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
of "supernode":
# In case of super node quarantine returns
# NUMBER_OF_COLUMNS div 2 + 1 columns which is enough for
# rebuild.
# In case of super node quarantine returns all
# NUMBER_OF_COLUMNS columns.
let
start = len(custodyColumns)
finish = start + len(custodyColumns) div 2 + 1
finish = start + len(custodyColumns)
sidecars.toOpenArray(start, finish - 1).mapIt(it.sidecar)
else:
raiseAssert "inaccessible"
Expand Down
Loading