|
23 | 23 | - [`compute_extended_matrix`](#compute_extended_matrix) |
24 | 24 | - [`recover_matrix`](#recover_matrix) |
25 | 25 | - [`get_data_column_sidecars`](#get_data_column_sidecars) |
| 26 | + - [`get_extended_sample_count`](#get_extended_sample_count) |
26 | 27 | - [Custody](#custody) |
27 | 28 | - [Custody requirement](#custody-requirement) |
28 | 29 | - [Public, deterministic selection](#public-deterministic-selection) |
|
31 | 32 | - [Column gossip](#column-gossip) |
32 | 33 | - [Parameters](#parameters) |
33 | 34 | - [Peer sampling](#peer-sampling) |
| 35 | + - [Sample selection](#sample-selection) |
| 36 | + - [Sample queries](#sample-queries) |
34 | 37 | - [Peer scoring](#peer-scoring) |
35 | 38 | - [Reconstruction and cross-seeding](#reconstruction-and-cross-seeding) |
36 | 39 | - [DAS providers](#das-providers) |
@@ -221,6 +224,48 @@ def get_data_column_sidecars(signed_block: SignedBeaconBlock, |
221 | 224 | return sidecars |
222 | 225 | ``` |
223 | 226 |
|
| 227 | +#### `get_extended_sample_count` |
| 228 | + |
| 229 | +```python |
| 230 | +def get_extended_sample_count(allowed_failures: uint64) -> uint64: |
| 231 | + assert 0 <= allowed_failures <= NUMBER_OF_COLUMNS // 2 |
| 232 | + """ |
| 233 | + Return the sample count if allowing failures. |
| 234 | +
|
| 235 | + This helper demonstrates how to calculate the number of columns to query per slot when |
| 236 | + allowing given number of failures, assuming uniform random selection without replacement. |
| 237 | + Nested functions are direct replacements of Python library functions math.comb and |
| 238 | + scipy.stats.hypergeom.cdf, with the same signatures. |
| 239 | + """ |
| 240 | + |
| 241 | + def math_comb(n: int, k: int) -> int: |
| 242 | + if not 0 <= k <= n: |
| 243 | + return 0 |
| 244 | + r = 1 |
| 245 | + for i in range(min(k, n - k)): |
| 246 | + r = r * (n - i) // (i + 1) |
| 247 | + return r |
| 248 | + |
| 249 | + def hypergeom_cdf(k: uint64, M: uint64, n: uint64, N: uint64) -> float: |
| 250 | + # NOTE: It contains float-point computations. |
| 251 | + # Convert uint64 to Python integers before computations. |
| 252 | + k = int(k) |
| 253 | + M = int(M) |
| 254 | + n = int(n) |
| 255 | + N = int(N) |
| 256 | + return sum([math_comb(n, i) * math_comb(M - n, N - i) / math_comb(M, N) |
| 257 | + for i in range(k + 1)]) |
| 258 | + |
| 259 | + worst_case_missing = NUMBER_OF_COLUMNS // 2 + 1 |
| 260 | + false_positive_threshold = hypergeom_cdf(0, NUMBER_OF_COLUMNS, |
| 261 | + worst_case_missing, SAMPLES_PER_SLOT) |
| 262 | + for sample_count in range(SAMPLES_PER_SLOT, NUMBER_OF_COLUMNS + 1): |
| 263 | + if hypergeom_cdf(allowed_failures, NUMBER_OF_COLUMNS, |
| 264 | + worst_case_missing, sample_count) <= false_positive_threshold: |
| 265 | + break |
| 266 | + return sample_count |
| 267 | +``` |
| 268 | + |
224 | 269 | ## Custody |
225 | 270 |
|
226 | 271 | ### Custody requirement |
@@ -263,7 +308,29 @@ Verifiable samples from their respective column are distributed on the assigned |
263 | 308 |
|
264 | 309 | ## Peer sampling |
265 | 310 |
|
266 | | -A node SHOULD maintain a diverse set of peers for each column and each slot by verifying responsiveness to sample queries. At each slot, a node makes `SAMPLES_PER_SLOT` queries for samples from their peers via `DataColumnSidecarsByRoot` request. A node utilizes `get_custody_columns` helper to determine which peer(s) to request from. If a node has enough good/honest peers across all rows and columns, this has a high chance of success. |
| 311 | +### Sample selection |
| 312 | + |
| 313 | +At each slot, a node SHOULD select at least `SAMPLES_PER_SLOT` column IDs for sampling. It is recommended to use uniform random selection without replacement based on local randomness. Sampling is considered successful if the node manages to retrieve all selected columns. |
| 314 | + |
| 315 | +Alternatively, a node MAY use a method that selects more than `SAMPLES_PER_SLOT` columns while allowing some missing, respecting the same target false positive threshold (the probability of successful sampling of an unavailable block) as dictated by the `SAMPLES_PER_SLOT` parameter. If using uniform random selection without replacement, a node can use the `get_extended_sample_count(allowed_failures) -> sample_count` helper function to determine the sample count (number of unique column IDs) for any selected number of allowed failures. Sampling is then considered successful if any `sample_count - allowed_failures` columns are retrieved successfully. |
| 316 | + |
| 317 | +For reference, the table below shows the number of samples and the number of allowed missing columns assuming `NUMBER_OF_COLUMNS = 128` and `SAMPLES_PER_SLOT = 16`. |
| 318 | + |
| 319 | +| Allowed missing | 0| 1| 2| 3| 4| 5| 6| 7| 8| |
| 320 | +|-----------------|--|--|--|--|--|--|--|--|--| |
| 321 | +| Sample count |16|20|24|27|29|32|35|37|40| |
| 322 | + |
| 323 | +### Sample queries |
| 324 | + |
| 325 | +A node SHOULD maintain a diverse set of peers for each column and each slot by verifying responsiveness to sample queries. |
| 326 | + |
| 327 | +A node SHOULD query for samples from selected peers via `DataColumnSidecarsByRoot` request. A node utilizes `get_custody_columns` helper to determine which peer(s) it could request from, identifying a list of candidate peers for each selected column. |
| 328 | + |
| 329 | +If more than one candidate peer is found for a given column, a node SHOULD randomize its peer selection to distribute sample query load in the network. Nodes MAY use peer scoring to tune this selection (for example, by using weighted selection or by using a cut-off threshold). If possible, it is also recommended to avoid requesting many columns from the same peer in order to avoid relying on and exposing the sample selection to a single peer. |
| 330 | + |
| 331 | +If a node already has a column because of custody, it is not required to send out queries for that column. |
| 332 | + |
| 333 | +If a node has enough good/honest peers across all columns, and the data is being made available, the above procedure has a high chance of success. |
267 | 334 |
|
268 | 335 | ## Peer scoring |
269 | 336 |
|
|
0 commit comments