Skip to content

Instantly share code, notes, and snippets.

@eth2353
Last active April 25, 2025 14:06
Show Gist options
  • Save eth2353/2b1cdf82b90a15a740f5ef2e1f2d07c9 to your computer and use it in GitHub Desktop.
Save eth2353/2b1cdf82b90a15a740f5ef2e1f2d07c9 to your computer and use it in GitHub Desktop.

This is a high-level analysis of blocks produced on the Hoodi testnet. I've reused some of the statistics that I looked at on the Holešky testnet after the Pectra incident. The aim is mostly to identify if any of the clients are doing something much better or much worse than others.

I'm leaving the interpretation to client teams.

Analysed epoch range: 2,248 - 2,748 and 8,450 – 8,550

General

Produced CL block value

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]   39,326,651 /   74,928,753 / ['20%: 22,760,000', '40%: 41,994,455', '60%: 43,363,166', '80%: 44,207,643']
Client.LIGHTHOUSE   : [681]   46,843,545 /  128,176,181 / ['20%: 41,100,465', '40%: 42,357,849', '60%: 43,085,722', '80%: 44,043,804']
Client.LODESTAR     : [732]   45,766,447 /  121,112,434 / ['20%: 40,118,604', '40%: 41,291,764', '60%: 42,065,438', '80%: 43,024,664']
Client.NIMBUS       : [748]   22,699,790 /  100,873,088 / ['20%:  2,047,826', '40%:  2,533,740', '60%: 40,269,822', '80%: 42,157,382']
Client.PRYSM        : [770]   48,883,144 /  107,039,934 / ['20%: 42,118,886', '40%: 43,483,601', '60%: 44,252,403', '80%: 46,284,012']
Client.TEKU         : [789]   42,862,826 /  101,743,465 / ['20%: 39,406,656', '40%: 41,039,653', '60%: 41,750,272', '80%: 42,637,180']
Client.UNKNOWN      : [10276] 45,737,969 /  164,016,308 / ['20%: 41,074,578', '40%: 42,383,749', '60%: 43,431,139', '80%: 44,883,610']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]    47,589,227 /   78,203,467 / ['20%: 45,742,361', '40%: 45,966,955', '60%: 46,320,917', '80%: 46,620,536']
Client.LIGHTHOUSE   : [127]    47,794,241 /   77,961,353 / ['20%: 45,606,549', '40%: 45,789,578', '60%: 45,930,292', '80%: 46,198,768']
Client.LODESTAR     : [136]    45,879,745 /   78,280,519 / ['20%: 44,931,206', '40%: 45,305,371', '60%: 45,433,888', '80%: 45,540,578']
Client.NIMBUS       : [155]    45,273,469 /  110,453,007 / ['20%: 45,228,935', '40%: 45,431,997', '60%: 45,608,321', '80%: 45,769,027']
Client.PRYSM        : [156]    48,855,158 /  107,574,476 / ['20%: 46,064,615', '40%: 46,349,501', '60%: 46,713,747', '80%: 47,634,652']
Client.TEKU         : [131]    43,768,215 /   75,107,582 / ['20%: 44,933,298', '40%: 45,311,709', '60%: 45,414,632', '80%: 45,561,778']
Client.UNKNOWN      : [2248]   46,738,936 /  112,355,567 / ['20%: 45,318,578', '40%: 45,544,071', '60%: 45,917,852', '80%: 46,600,136']
Produced CL block value - attestations only

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]   37,851,405 /   73,411,123 / ['20%: 21,216,895', '40%: 40,504,581', '60%: 41,865,383', '80%: 42,712,117']
Client.LIGHTHOUSE   : [681]   45,361,533 /  126,709,761 / ['20%: 39,620,678', '40%: 40,870,607', '60%: 41,574,072', '80%: 42,525,288']
Client.LODESTAR     : [732]   44,303,136 /  119,686,542 / ['20%: 38,598,857', '40%: 39,795,745', '60%: 40,546,216', '80%: 41,507,962']
Client.NIMBUS       : [748]   21,230,357 /   99,359,576 / ['20%:    576,826', '40%:  1,060,528', '60%: 38,825,458', '80%: 40,669,827']
Client.PRYSM        : [770]   47,423,392 /  105,526,002 / ['20%: 40,684,730', '40%: 41,992,460', '60%: 42,738,468', '80%: 44,798,186']
Client.TEKU         : [789]   41,429,067 /  100,235,522 / ['20%: 37,940,690', '40%: 39,558,236', '60%: 40,249,864', '80%: 41,145,051']
Client.UNKNOWN      : [10276] 44,260,912 /  162,448,303 / ['20%: 39,615,449', '40%: 40,884,750', '60%: 41,923,257', '80%: 43,372,489']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]   45,952,319 /   76,563,553 / ['20%: 44,120,523', '40%: 44,326,743', '60%: 44,680,804', '80%: 44,987,623']
Client.LIGHTHOUSE   :  [127]   46,159,969 /   76,311,560 / ['20%: 43,965,639', '40%: 44,149,265', '60%: 44,280,499', '80%: 44,574,097']
Client.LODESTAR     :  [136]   44,258,765 /   76,630,726 / ['20%: 43,304,334', '40%: 43,660,746', '60%: 43,793,974', '80%: 43,901,919']
Client.NIMBUS       :  [155]   43,638,009 /  108,812,595 / ['20%: 43,588,523', '40%: 43,799,637', '60%: 43,969,020', '80%: 44,123,053']
Client.PRYSM        :  [156]   47,235,922 /  105,934,562 / ['20%: 44,426,747', '40%: 44,715,708', '60%: 45,073,335', '80%: 46,040,280']
Client.TEKU         :  [131]   42,170,435 /   73,467,668 / ['20%: 43,310,877', '40%: 43,671,958', '60%: 43,770,197', '80%: 43,917,249']
Client.UNKNOWN      : [2248]   45,110,138 /  110,715,155 / ['20%: 43,678,867', '40%: 43,903,705', '60%: 44,285,859', '80%: 44,957,107']
Number of attestations included in block

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]         7.22 /            8 / ['20%: 7.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.LIGHTHOUSE   : [681]         7.82 /            8 / ['20%: 8.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.LODESTAR     : [732]         5.75 /            8 / ['20%: 4.0', '40%: 5.0', '60%: 6.0', '80%: 8.0']  
Client.NIMBUS       : [748]         7.95 /            8 / ['20%: 8.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.PRYSM        : [770]         8.00 /            8 / ['20%: 8.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.TEKU         : [789]         5.02 /            8 / ['20%: 3.0', '40%: 4.0', '60%: 5.0', '80%: 8.0']  
Client.UNKNOWN      : [10276]       7.11 /            8 / ['20%: 6.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]         6.08 /            8 / ['20%: 3.8', '40%: 6.0', '60%: 8.0', '80%: 8.0']  
Client.LIGHTHOUSE   :  [127]         7.02 /            8 / ['20%: 5.6', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.LODESTAR     :  [136]         2.32 /            8 / ['20%: 1.0', '40%: 2.0', '60%: 2.0', '80%: 3.0']  
Client.NIMBUS       :  [155]         5.34 /            8 / ['20%: 2.0', '40%: 4.0', '60%: 7.0', '80%: 8.0']  
Client.PRYSM        :  [156]         8.00 /            8 / ['20%: 8.0', '40%: 8.0', '60%: 8.0', '80%: 8.0']  
Client.TEKU         :  [131]         2.40 /            7 / ['20%: 1.0', '40%: 2.0', '60%: 2.0', '80%: 3.0']  
Client.UNKNOWN      : [2248]         5.41 /            8 / ['20%: 2.0', '40%: 4.0', '60%: 8.0', '80%: 8.0']
Code
len(block.message.body.attestations)
Number of single attestations included in block

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]       48,466 /       63,701 / ['20%: 34,581', '40%: 48,591', '60%: 54,940', '80%: 58,810']
Client.LIGHTHOUSE   : [681]       88,106 /      180,604 / ['20%: 65,603', '40%: 90,240', '60%: 93,445', '80%: 95,349']
Client.LODESTAR     : [732]       54,033 /      163,403 / ['20%: 40,132', '40%: 46,120', '60%: 51,264', '80%: 61,393']
Client.NIMBUS       : [748]       36,303 /      106,595 / ['20%: 18,749', '40%: 31,222', '60%: 40,846', '80%: 51,242']
Client.PRYSM        : [770]       56,431 /      118,826 / ['20%: 42,848', '40%: 48,912', '60%: 57,161', '80%: 69,502']
Client.TEKU         : [789]       45,986 /      160,492 / ['20%: 34,777', '40%: 39,777', '60%: 44,509', '80%: 51,766']
Client.UNKNOWN      : [10276]     76,769 /      241,322 / ['20%: 48,485', '40%: 64,232', '60%: 90,993', '80%: 94,748'] 

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]       49,778 /       67,848 / ['20%: 36,079', '40%:  43,986', '60%:  53,827', '80%:  64,250']
Client.LIGHTHOUSE   :  [127]       86,092 /      180,247 / ['20%: 67,699', '40%: 100,375', '60%: 101,626', '80%: 102,117']
Client.LODESTAR     :  [136]       36,155 /       81,507 / ['20%: 33,602', '40%:  33,718', '60%:  34,084', '80%:  35,491']
Client.NIMBUS       :  [155]       41,355 /      102,524 / ['20%: 33,773', '40%:  36,747', '60%:  39,966', '80%:  49,355']
Client.PRYSM        :  [156]       58,158 /      138,026 / ['20%: 40,774', '40%:  49,308', '60%:  56,863', '80%:  75,011']
Client.TEKU         :  [131]       34,174 /       73,982 / ['20%: 33,520', '40%:  33,688', '60%:  34,054', '80%:  34,991']
Client.UNKNOWN      : [2248]       57,392 /      207,527 / ['20%: 34,028', '40%:  39,203', '60%:  59,497', '80%:  80,296']
Code
sum(sum(att.aggregation_bits) for att in block.message.body.attestations)
Number of unique attesters voting for any slot whose attestation was included

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]    48,291.61 /       63,701 / ['20%: 34,580.6', '40%: 48,241.4', '60%: 54,658.0', '80%: 58,575.4']
Client.LIGHTHOUSE   : [681]    86,728.10 /      170,960 / ['20%: 63,257.6', '40%: 89,100.8', '60%: 92,224.4', '80%: 93,947.4']
Client.LODESTAR     : [732]    42,892.32 /      111,489 / ['20%: 31,390.8', '40%: 37,710.2', '60%: 42,353.2', '80%: 49,633.8']
Client.NIMBUS       : [748]    36,184.86 /      106,595 / ['20%: 18,694.6', '40%: 31,202.4', '60%: 40,708.2', '80%: 51,025.6']
Client.PRYSM        : [770]    52,371.72 /      101,589 / ['20%: 40,055.0', '40%: 46,020.6', '60%: 53,542.4', '80%: 64,065.6']
Client.TEKU         : [789]    40,992.10 /      154,751 / ['20%: 30,481.0', '40%: 35,278.0', '60%: 40,003.0', '80%: 45,659.0']
Client.UNKNOWN      : [10276]  74,090.25 /      215,444 / ['20%: 45,506.0', '40%: 62,278.0', '60%: 89,664.2', '80%: 93,488.6']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]    49,635.44 /       67,848 / ['20%: 35,798.8', '40%: 43,966.4', '60%:  53,817.8', '80%:  64,044.2']
Client.LIGHTHOUSE   :  [127]    85,079.04 /      180,225 / ['20%: 67,205.8', '40%: 97,632.6', '60%: 101,011.8', '80%: 101,303.8']
Client.LODESTAR     :  [136]    35,268.51 /       77,140 / ['20%: 33,396.2', '40%: 33,546.0', '60%:  33,631.6', '80%:  33,755.2']
Client.NIMBUS       :  [155]    41,308.34 /      102,524 / ['20%: 33,773.0', '40%: 36,747.0', '60%:  39,966.4', '80%:  49,355.4']
Client.PRYSM        :  [156]    56,145.21 /      134,702 / ['20%: 39,739.0', '40%: 47,701.2', '60%:  55,925.0', '80%:  72,491.8']
Client.TEKU         :  [131]    33,243.10 /       64,979 / ['20%: 33,386.8', '40%: 33,547.6', '60%:  33,612.6', '80%:  33,822.6']
Client.UNKNOWN      : [2248]    55,796.18 /      199,482 / ['20%: 33,622.8', '40%: 37,469.6', '60%:  57,434.2', '80%:  76,321.0']
Code
unique_attesters_included_in_block = set()

for att in block.message.body.attestations:
    commmitees = await get_committee(state_id=att.data.slot)

    agg_bits_offset = 0

    for committee in commmitees:
        idx = int(committee["index"])
        if att.committee_bits[idx] == 1:
            val_count = len(committee["validators"])
            committee_agg_bits = att.aggregation_bits[
                                 agg_bits_offset:agg_bits_offset + val_count]
            agg_bits_offset += val_count

            for val_committee_idx, val_idx in enumerate(committee["validators"]):
                if committee_agg_bits[val_committee_idx] == 1:
                    unique_attesters_included_in_block.add(val_idx)
% of unique single attestations vs total single attestations included (max possible: 100%)

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]        99.66 /          100 / ['20%: 99.3', '40%: 99.8', '60%: 100.0', '80%: 100.0']
Client.LIGHTHOUSE   : [681]        98.39 /          100 / ['20%: 97.8', '40%: 98.3', '60%:  98.7', '80%:  99.3']
Client.LODESTAR     : [732]        80.91 /           98 / ['20%: 72.0', '40%: 79.3', '60%:  84.7', '80%:  90.0']
Client.NIMBUS       : [748]        99.72 /          100 / ['20%: 99.5', '40%: 99.7', '60%: 100.0', '80%: 100.0']
Client.PRYSM        : [770]        93.19 /          100 / ['20%: 90.3', '40%: 92.9', '60%:  95.1', '80%:  96.9']
Client.TEKU         : [789]        89.70 /          100 / ['20%: 84.0', '40%: 89.2', '60%:  92.9', '80%:  95.9']
Client.UNKNOWN      : [10276]      96.64 /          100 / ['20%: 96.3', '40%: 98.2', '60%:  98.9', '80%:  99.6']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]        99.68 /          100 / ['20%: 99.7', '40%: 100.0', '60%: 100.0', '80%: 100.0']
Client.LIGHTHOUSE   : [127]        98.71 /          100 / ['20%: 98.0', '40%: 98.7', '60%: 99.3', '80%: 99.6']
Client.LODESTAR     : [136]        97.73 /          100 / ['20%: 96.8', '40%: 98.7', '60%: 99.9', '80%: 100.0']
Client.NIMBUS       : [155]        99.90 /          100 / ['20%: 99.9', '40%: 100.0', '60%: 100.0', '80%: 100.0']
Client.PRYSM        : [156]        96.76 /          100 / ['20%: 95.4', '40%: 97.1', '60%: 97.9', '80%: 98.6']
Client.TEKU         : [131]        97.69 /          100 / ['20%: 97.4', '40%: 98.7', '60%: 100.0', '80%: 100.0']
Client.UNKNOWN      : [2248]        97.53 /          100 / ['20%: 97.1', '40%: 98.5', '60%: 99.3', '80%: 100.0']
Code
total_single_attestations_included = 0
unique_attesters_included_in_block = set()

for att in block.message.body.attestations:
    commmitees = await get_committee(state_id=att.data.slot)

    agg_bits_offset = 0

    for committee in commmitees:
        idx = int(committee["index"])
        if att.committee_bits[idx] == 1:
            val_count = len(committee["validators"])
            committee_agg_bits = att.aggregation_bits[
                                 agg_bits_offset:agg_bits_offset + val_count]
            agg_bits_offset += val_count

            total_single_attestations_included += sum(committee_agg_bits)

            for val_committee_idx, val_idx in enumerate(committee["validators"]):
                if committee_agg_bits[val_committee_idx] == 1:
                    unique_attesters_included_in_block.add(val_idx)

ratio = len(unique_attesters_included_in_block) / total_single_attestations_included
Weighted mean attestation inclusion distance in blocks built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]         3.47 /           15 / ['20%: 2.0', '40%: 2.5', '60%: 3.2', '80%:  4.7']  
Client.LIGHTHOUSE   : [681]         2.16 /           14 / ['20%: 1.9', '40%: 2.0', '60%: 2.0', '80%:  2.0']  
Client.LODESTAR     : [732]         1.34 /            4 / ['20%: 1.1', '40%: 1.2', '60%: 1.3', '80%:  1.5']  
Client.NIMBUS       : [748]         7.29 /           21 / ['20%: 3.1', '40%: 4.8', '60%: 7.4', '80%: 12.0'] 
Client.PRYSM        : [770]         1.52 /            4 / ['20%: 1.3', '40%: 1.4', '60%: 1.5', '80%:  1.7']  
Client.TEKU         : [789]         1.62 /           22 / ['20%: 1.1', '40%: 1.2', '60%: 1.3', '80%:  1.6']  
Client.UNKNOWN      : [10276]       2.34 /           30 / ['20%: 1.5', '40%: 2.0', '60%: 2.0', '80%:  2.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]         1.87 /            6 / ['20%: 1.2', '40%: 1.6', '60%: 1.9', '80%: 2.3']  
Client.LIGHTHOUSE   :  [127]         1.86 /            8 / ['20%: 1.5', '40%: 2.0', '60%: 2.0', '80%: 2.0']  
Client.LODESTAR     :  [136]         1.04 /            2 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.NIMBUS       :  [155]         2.03 /           12 / ['20%: 1.0', '40%: 1.3', '60%: 1.7', '80%: 2.3']  
Client.PRYSM        :  [156]         2.60 /           16 / ['20%: 1.5', '40%: 1.9', '60%: 2.2', '80%: 3.1']  
Client.TEKU         :  [131]         1.05 /            2 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.UNKNOWN      : [2248]         1.91 /           19 / ['20%: 1.0', '40%: 1.4', '60%: 1.9', '80%: 2.2'] 
Code
weighted_mean_denominator = sum(sum(att.aggregation_bits) for att in block.message.body.attestations)

weighted_mean_attestation_inclusion_distance = sum((sum(att.aggregation_bits) / weighted_mean_denominator) * (block_slot - att.data.slot) for att in block.message.body.attestations)
Minimal attestation inclusion distance in blocks built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.LIGHTHOUSE   : [681]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.LODESTAR     : [732]         1.00 /            2 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.NIMBUS       : [748]         2.06 /           16 / ['20%: 1.0', '40%: 1.0', '60%: 2.0', '80%: 3.0']  
Client.PRYSM        : [770]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.TEKU         : [789]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.UNKNOWN      : [10276]       1.07 /           14 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0'] 

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.LIGHTHOUSE   :  [127]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.LODESTAR     :  [136]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.NIMBUS       :  [155]         1.08 /            6 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.PRYSM        :  [156]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.TEKU         :  [131]         1.00 /            1 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.UNKNOWN      : [2248]         1.01 /            7 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0'] 
Code
min(block_slot - att.data.slot for att in block.message.body.attestations)
% of fresh attestations in blocks built by client

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]        75.35 /          100 / ['20%: 55.0', '40%: 66.4', '60%: 82.3', '80%: 97.0']
Client.LIGHTHOUSE   :  [127]        48.77 /          100 / ['20%: 33.3', '40%: 33.5', '60%: 48.0', '80%: 65.8']
Client.LODESTAR     :  [136]        95.87 /          100 / ['20%: 94.5', '40%: 98.5', '60%: 99.5', '80%: 100.0']
Client.NIMBUS       :  [155]        81.66 /          100 / ['20%: 69.2', '40%: 83.3', '60%: 90.3', '80%: 98.4']
Client.PRYSM        :  [156]        68.37 /           98 / ['20%: 53.2', '40%: 63.9', '60%: 73.7', '80%: 84.8']
Client.TEKU         :  [131]        94.94 /          100 / ['20%: 95.3', '40%: 98.5', '60%: 99.8', '80%: 100.0']
Client.UNKNOWN      : [2248]        71.16 /          100 / ['20%: 46.7', '40%: 61.9', '60%: 87.9', '80%: 98.5']
Code
for attestation in block.message.body.attestations:
    attesters_in_attestation = ...

    first_seen_attestations_in_block += len(set(attesters_in_att) - EPOCH_ATTESTER_TRACKER[att_for_block_in_epoch])
    previously_seen_attestations_in_block += len(set(attesters_in_att).intersection(EPOCH_ATTESTER_TRACKER[att_for_block_in_epoch]))
    EPOCH_ATTESTER_TRACKER[att_for_block_in_epoch].update(attesters_in_att)

fresh_attestation_ratio = first_seen_attestations_in_block / (first_seen_attestations_in_block + previously_seen_attestations_in_block)

Target Correctness

Unique attesters voting for correct target included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]       48,082 /       63,701 / ['20%: 34,438', '40%: 47,907', '60%: 54,648', '80%: 58,575']
Client.LIGHTHOUSE   : [681]       86,667 /      170,960 / ['20%: 63,171', '40%: 89,040', '60%: 92,224', '80%: 93,947']
Client.LODESTAR     : [732]       42,892 /      111,489 / ['20%: 31,391', '40%: 37,710', '60%: 42,353', '80%: 49,634']
Client.NIMBUS       : [748]       36,130 /      106,595 / ['20%: 18,674', '40%: 31,090', '60%: 40,606', '80%: 51,026']
Client.PRYSM        : [770]       52,297 /      101,589 / ['20%: 40,055', '40%: 45,963', '60%: 53,489', '80%: 64,048']
Client.TEKU         : [789]       40,934 /      154,751 / ['20%: 30,469', '40%: 35,177', '60%: 39,996', '80%: 45,621']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]       49,626 /       67,848 / ['20%: 35,799', '40%: 43,966', '60%:  53,517', '80%:  64,044']
Client.LIGHTHOUSE   : [127]       85,060 /      180,225 / ['20%: 67,206', '40%: 97,633', '60%: 101,012', '80%: 101,304']
Client.LODESTAR     : [136]       35,058 /       77,140 / ['20%: 33,396', '40%: 33,546', '60%:  33,632', '80%:  33,755']
Client.NIMBUS       : [155]       41,297 /      102,524 / ['20%: 33,759', '40%: 36,747', '60%:  39,966', '80%:  49,355']
Client.PRYSM        : [156]       55,681 /      134,702 / ['20%: 39,739', '40%: 47,429', '60%:  55,160', '80%:  70,665']
Client.TEKU         : [131]       33,243 /       64,979 / ['20%: 33,387', '40%: 33,548', '60%:  33,613', '80%:  33,823']
Code
def get_correct_target_checkpoint(attestation_slot: int) -> tuple[int, str]:
    epoch_boundary_slot = 32 * (attestation_slot // 32)

    target_slot = epoch_boundary_slot

    while True:
        try:
            client_used, block_data = get_raw_block(target_slot)
            break
        except BlockNotFound:
            target_slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)

    return target_slot // 32, "0x" + block.message.hash_tree_root().hex()

unique_attesters_voting_for_correct_target_included_in_block = set()
unique_attesters_voting_for_incorrect_target_included_in_block = set()
  
for att in block.message.body.attestations:
    correct_target_epoch, correct_target_block_root = get_correct_target_checkpoint(att.data.slot)
    is_voting_for_correct_target = str(att.data.target.root) == correct_target_block_root

    for committee in commmitees:
      idx = int(committee["index"])
      if att.committee_bits[idx] == 1:
          for val_committee_idx, val_idx in enumerate(committee["validators"]):
              if committee_agg_bits[val_committee_idx] == 1:
                  if is_voting_for_correct_target:
                      unique_attesters_voting_for_correct_target_included_in_block.add(val_idx)
                  else:
                      unique_attesters_voting_for_incorrect_target_included_in_block.add(val_idx)
Unique attesters voting for incorrect target included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [145]        2,102 /       28,077 / ['20%: 0', '40%: 0', '60%: 0', '80%: 1,891']      
Client.LIGHTHOUSE   : [127]        1,738 /       29,632 / ['20%: 0', '40%: 0', '60%: 0', '80%:     0']          
Client.LODESTAR     : [149]        1,346 /       29,329 / ['20%: 0', '40%: 0', '60%: 0', '80%:     0']          
Client.NIMBUS       : [131]        1,478 /       29,992 / ['20%: 0', '40%: 0', '60%: 0', '80%:   985']        
Client.PRYSM        : [156]        1,529 /       30,020 / ['20%: 0', '40%: 0', '60%: 0', '80%:     0']          
Client.TEKU         : [178]        1,261 /       29,428 / ['20%: 0', '40%: 0', '60%: 0', '80%:     0']    

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]           10 /        1,277 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.LIGHTHOUSE   : [127]           19 /        2,414 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.LODESTAR     : [136]          210 /       28,541 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.NIMBUS       : [155]           11 /          577 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.PRYSM        : [156]          477 /       27,515 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.TEKU         : [131]            0 /            0 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0'] 
Code
def get_correct_target_checkpoint(attestation_slot: int) -> tuple[int, str]:
    epoch_boundary_slot = 32 * (attestation_slot // 32)

    target_slot = epoch_boundary_slot

    while True:
        try:
            client_used, block_data = get_raw_block(target_slot)
            break
        except BlockNotFound:
            target_slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)

    return target_slot // 32, "0x" + block.message.hash_tree_root().hex()

unique_attesters_voting_for_correct_target_included_in_block = set()
unique_attesters_voting_for_incorrect_target_included_in_block = set()
  
for att in block.message.body.attestations:
    correct_target_epoch, correct_target_block_root = get_correct_target_checkpoint(att.data.slot)
    is_voting_for_correct_target = str(att.data.target.root) == correct_target_block_root

    for committee in commmitees:
      idx = int(committee["index"])
      if att.committee_bits[idx] == 1:
          for val_committee_idx, val_idx in enumerate(committee["validators"]):
              if committee_agg_bits[val_committee_idx] == 1:
                  if is_voting_for_correct_target:
                      unique_attesters_voting_for_correct_target_included_in_block.add(val_idx)
                  else:
                      unique_attesters_voting_for_incorrect_target_included_in_block.add(val_idx)
Unique attesters voting for previous epoch target included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]        3,836 /       40,401 / ['20%: 0', '40%:   0', '60%: 1,307', '80%:  5,464']  
Client.LIGHTHOUSE   : [681]        5,397 /      124,804 / ['20%: 0', '40%:   0', '60%:     0', '80%:      0']          
Client.LODESTAR     : [732]        2,556 /       79,759 / ['20%: 0', '40%:   0', '60%:     0', '80%:      0']          
Client.NIMBUS       : [748]        7,019 /       82,923 / ['20%: 0', '40%: 990', '60%: 5,398', '80%: 12,106']
Client.PRYSM        : [770]        2,105 /       98,970 / ['20%: 0', '40%:   0', '60%:     0', '80%:      0']          
Client.TEKU         : [789]        2,508 /       92,119 / ['20%: 0', '40%:   0', '60%:     0', '80%:      0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]        1,814 /       52,540 / ['20%: 0', '40%: 0', '60%:   0', '80%:   560']        
Client.LIGHTHOUSE   : [127]        4,910 /      101,295 / ['20%: 0', '40%: 0', '60%:   0', '80%:     0']          
Client.LODESTAR     : [136]        2,724 /       65,436 / ['20%: 0', '40%: 0', '60%:   0', '80%:     0']          
Client.NIMBUS       : [155]        2,298 /       38,399 / ['20%: 0', '40%: 0', '60%:   0', '80%: 2,096']      
Client.PRYSM        : [156]        4,853 /       71,551 / ['20%: 0', '40%: 0', '60%: 843', '80%: 4,676']    
Client.TEKU         : [131]          573 /       33,615 / ['20%: 0', '40%: 0', '60%:   0', '80%:     0']   
Code
unique_attesters_voting_for_target_prev_epoch = set()
unique_attesters_voting_for_target_current_epoch = set()
  
for att in block.message.body.attestations:
  is_current_epoch_target = att.data.target.epoch == block_slot // 32
  
  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_current_epoch_target:
            unique_attesters_voting_for_target_current_epoch.add(val_idx)
          else:
            unique_attesters_voting_for_target_prev_epoch.add(val_idx)
Unique attesters voting for current epoch target included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]       44,558 /       63,701 / ['20%: 32,788', '40%: 43,242', '60%: 51,997', '80%: 57,305']
Client.LIGHTHOUSE   : [681]       81,489 /      170,960 / ['20%: 61,376', '40%: 87,079', '60%: 92,061', '80%: 93,240']
Client.LODESTAR     : [732]       40,360 /      111,489 / ['20%: 30,099', '40%: 36,584', '60%: 41,505', '80%: 48,008']
Client.NIMBUS       : [748]       29,285 /      106,595 / ['20%:  8,574', '40%: 22,218', '60%: 34,493', '80%: 46,644']
Client.PRYSM        : [770]       50,300 /      101,589 / ['20%: 38,308', '40%: 44,575', '60%: 52,485', '80%: 63,463']
Client.TEKU         : [789]       38,538 /      127,405 / ['20%: 29,918', '40%: 33,711', '60%: 39,110', '80%: 44,045']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]       47,846 /       67,848 / ['20%: 34,358', '40%: 41,823', '60%:  53,351', '80%:  63,811']
Client.LIGHTHOUSE   : [127]       80,333 /      180,225 / ['20%: 52,267', '40%: 67,593', '60%: 100,997', '80%: 101,300']
Client.LODESTAR     : [136]       32,545 /       77,140 / ['20%: 33,148', '40%: 33,484', '60%:  33,608', '80%:  33,724']
Client.NIMBUS       : [155]       39,057 /      102,524 / ['20%: 33,624', '40%: 35,607', '60%:  38,483', '80%:  46,951']
Client.PRYSM        : [156]       51,428 /      134,702 / ['20%: 36,446', '40%: 41,738', '60%:  52,455', '80%:  64,995']
Client.TEKU         : [131]       32,671 /       64,979 / ['20%: 33,361', '40%: 33,544', '60%:  33,608', '80%:  33,823']
Code
unique_attesters_voting_for_target_prev_epoch = set()
unique_attesters_voting_for_target_current_epoch = set()
  
for att in block.message.body.attestations:
  is_current_epoch_target = att.data.target.epoch == block_slot // 32
  
  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_current_epoch_target:
            unique_attesters_voting_for_target_current_epoch.add(val_idx)
          else:
            unique_attesters_voting_for_target_prev_epoch.add(val_idx)
Unique attesters voting for correct target *managed by* client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [14608]        2,869 /       11,056 / ['20%: 1,537', '40%: 2,313', '60%: 3,168', '80%: 4,672']
Client.LIGHTHOUSE   : [14608]        3,349 /       10,767 / ['20%: 1,975', '40%: 2,857', '60%: 4,215', '80%: 4,605']
Client.LODESTAR     : [14608]        3,429 /       10,971 / ['20%: 2,013', '40%: 2,922', '60%: 4,454', '80%: 4,698']
Client.NIMBUS       : [14608]        3,440 /       10,988 / ['20%: 2,017', '40%: 2,935', '60%: 4,483', '80%: 4,698']
Client.PRYSM        : [14608]        3,414 /       11,046 / ['20%: 1,993', '40%: 2,920', '60%: 4,400', '80%: 4,694']
Client.TEKU         : [14608]        3,350 /       11,009 / ['20%: 1,975', '40%: 2,830', '60%: 4,046', '80%: 4,666']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [3096]        2,490 /        9,062 / ['20%: 1,569', '40%: 1,676', '60%: 2,416', '80%: 3,242']
Client.LIGHTHOUSE   : [3096]        2,494 /        9,166 / ['20%: 1,437', '40%: 1,648', '60%: 2,726', '80%: 3,649']
Client.LODESTAR     : [3096]        2,486 /        9,193 / ['20%: 1,570', '40%: 1,687', '60%: 2,370', '80%: 3,228']
Client.NIMBUS       : [3096]        2,492 /        9,207 / ['20%: 1,569', '40%: 1,681', '60%: 2,398', '80%: 3,231']
Client.PRYSM        : [3096]        2,484 /        9,151 / ['20%: 1,569', '40%: 1,682', '60%: 2,392', '80%: 3,229']
Client.TEKU         : [3096]        2,444 /        9,127 / ['20%: 1,561', '40%: 1,670', '60%: 2,398', '80%: 3,239']
Code
def get_correct_target_checkpoint(attestation_slot: int) -> tuple[int, str]:
    epoch_boundary_slot = 32 * (attestation_slot // 32)

    target_slot = epoch_boundary_slot

    while True:
        try:
            client_used, block_data = get_raw_block(target_slot)
            break
        except BlockNotFound:
            target_slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)

    return target_slot // 32, "0x" + block.message.hash_tree_root().hex()

attesting_client_unique_attesters_correct_target = {c: set() for c in Client}
  
for att in block.message.body.attestations:
    correct_target_epoch, correct_target_block_root = get_correct_target_checkpoint(att.data.slot)
    is_voting_for_correct_target = str(att.data.target.root) == correct_target_block_root

    for committee in commmitees:
      idx = int(committee["index"])
      if att.committee_bits[idx] == 1:
          for val_committee_idx, val_idx in enumerate(committee["validators"]):
              if committee_agg_bits[val_committee_idx] == 1:
                  if is_voting_for_correct_target:
                      attesting_client_unique_attesters_correct_target[get_client_for_validator_idx(int(val_idx))].add(val_idx)

Head Correctness

Unique attesters voting for correct head included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]       47,922 /       63,701 / ['20%: 34,317', '40%: 47,724', '60%: 54,597', '80%: 58,503']
Client.LIGHTHOUSE   : [681]       86,336 /      170,960 / ['20%: 63,046', '40%: 88,974', '60%: 92,177', '80%: 93,914']
Client.LODESTAR     : [732]       42,472 /      111,489 / ['20%: 31,080', '40%: 37,501', '60%: 42,268', '80%: 49,284']
Client.NIMBUS       : [748]       35,881 /      106,595 / ['20%: 18,537', '40%: 30,785', '60%: 40,291', '80%: 50,767']
Client.PRYSM        : [770]       51,990 /      101,587 / ['20%: 39,722', '40%: 45,778', '60%: 53,170', '80%: 63,602']
Client.TEKU         : [789]       40,698 /      154,187 / ['20%: 30,356', '40%: 34,878', '60%: 39,928', '80%: 45,475']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]       49,597 /       67,848 / ['20%: 35,798', '40%: 43,961', '60%:  53,451', '80%:  64,044']
Client.LIGHTHOUSE   : [127]       85,054 /      180,225 / ['20%: 67,096', '40%: 97,633', '60%: 101,012', '80%: 101,291']
Client.LODESTAR     : [136]       35,046 /       76,187 / ['20%: 33,396', '40%: 33,546', '60%:  33,632', '80%:  33,755']
Client.NIMBUS       : [155]       41,290 /      102,504 / ['20%: 33,758', '40%: 36,700', '60%:  39,963', '80%:  49,355']
Client.PRYSM        : [156]       55,665 /      134,702 / ['20%: 39,738', '40%: 47,403', '60%:  55,160', '80%:  70,348']
Client.TEKU         : [131]       33,242 /       64,979 / ['20%: 33,387', '40%: 33,548', '60%:  33,610', '80%:  33,823']
Code
def get_correct_head_root(slot: int) -> str:
    while True:
        try:
            client_used, block_data = get_raw_block(slot)
            break
        except BlockNotFound:
            slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)
    return "0x" + block.message.hash_tree_root().hex()

unique_attesters_voting_for_correct_head_included_in_block = set()
unique_attesters_voting_for_incorrect_head_included_in_block = set()
  
for att in block.message.body.attestations:
  correct_head_root = get_correct_head_root(att.data.slot)
  is_voting_for_correct_head = str(att.data.beacon_block_root) == correct_head_root

  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_voting_for_correct_head:
            unique_attesters_voting_for_correct_head_included_in_block.add(val_idx)
          else:
            unique_attesters_voting_for_incorrect_head_included_in_block.add(val_idx)
Unique attesters voting for incorrect head included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]          375 /       30,298 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.LIGHTHOUSE   : [681]          397 /       31,056 / ['20%: 0', '40%: 0', '60%: 0', '80%: 1']          
Client.LODESTAR     : [732]          420 /       30,629 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.NIMBUS       : [748]          307 /       59,440 / ['20%: 0', '40%: 1', '60%: 2', '80%: 5']          
Client.PRYSM        : [770]          382 /       59,698 / ['20%: 0', '40%: 3', '60%: 5', '80%: 7']          
Client.TEKU         : [789]          300 /       31,983 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]           39 /        1,943 / ['20%: 0', '40%: 0', '60%: 2', '80%: 4']          
Client.LIGHTHOUSE   : [127]           25 /        2,471 / ['20%: 0', '40%: 0', '60%: 0', '80%: 1']          
Client.LODESTAR     : [136]          223 /       28,541 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']          
Client.NIMBUS       : [155]           18 /          578 / ['20%: 0', '40%: 0', '60%: 1', '80%: 7']          
Client.PRYSM        : [156]          494 /       27,515 / ['20%: 0', '40%: 0', '60%: 0', '80%: 3']          
Client.TEKU         : [131]            1 /          154 / ['20%: 0', '40%: 0', '60%: 0', '80%: 0']
Code
def get_correct_head_root(slot: int) -> str:
    while True:
        try:
            client_used, block_data = get_raw_block(slot)
            break
        except BlockNotFound:
            slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)
    return "0x" + block.message.hash_tree_root().hex()

unique_attesters_voting_for_correct_head_included_in_block = set()
unique_attesters_voting_for_incorrect_head_included_in_block = set()
  
for att in block.message.body.attestations:
  correct_head_root = get_correct_head_root(att.data.slot)
  is_voting_for_correct_head = str(att.data.beacon_block_root) == correct_head_root

  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_voting_for_correct_head:
            unique_attesters_voting_for_correct_head_included_in_block.add(val_idx)
          else:
            unique_attesters_voting_for_incorrect_head_included_in_block.add(val_idx)
Unique attesters voting for correct head *managed by* client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [14608]        2,858 /       11,056 / ['20%: 1,532', '40%: 2,300', '60%: 3,162', '80%: 4,670']
Client.LIGHTHOUSE   : [14608]        3,333 /       10,767 / ['20%: 1,962', '40%: 2,845', '60%: 4,175', '80%: 4,603']
Client.LODESTAR     : [14608]        3,410 /       10,971 / ['20%: 2,000', '40%: 2,903', '60%: 4,380', '80%: 4,696']
Client.NIMBUS       : [14608]        3,424 /       10,988 / ['20%: 2,004', '40%: 2,920', '60%: 4,441', '80%: 4,697']
Client.PRYSM        : [14608]        3,395 /       11,046 / ['20%: 1,978', '40%: 2,894', '60%: 4,314', '80%: 4,692']
Client.TEKU         : [14608]        3,326 /       11,009 / ['20%: 1,958', '40%: 2,799', '60%: 3,954', '80%: 4,665']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [3096]        2,490 /        9,062 / ['20%: 1,569', '40%: 1,676', '60%: 2,416', '80%: 3,242']
Client.LIGHTHOUSE   : [3096]        2,492 /        9,166 / ['20%: 1,437', '40%: 1,648', '60%: 2,724', '80%: 3,641']
Client.LODESTAR     : [3096]        2,484 /        9,193 / ['20%: 1,570', '40%: 1,686', '60%: 2,369', '80%: 3,222']
Client.NIMBUS       : [3096]        2,492 /        9,207 / ['20%: 1,569', '40%: 1,681', '60%: 2,398', '80%: 3,231']
Client.PRYSM        : [3096]        2,481 /        9,151 / ['20%: 1,569', '40%: 1,682', '60%: 2,391', '80%: 3,225']
Client.TEKU         : [3096]        2,441 /        9,127 / ['20%: 1,561', '40%: 1,669', '60%: 2,391', '80%: 3,228']
Code
def get_correct_head_root(slot: int) -> str:
    while True:
        try:
            client_used, block_data = get_raw_block(slot)
            break
        except BlockNotFound:
            slot -= 1

    block = SpecBeaconBlock.ElectraBlockSigned.from_obj(block_data)
    return "0x" + block.message.hash_tree_root().hex()

attesting_client_unique_attesters_correct_head = {c: set() for c in Client}

for att in block.message.body.attestations:
    is_voting_for_correct_head = str(att.data.beacon_block_root) == get_correct_head_root(att.data.slot)

    for committee in commmitees:
      idx = int(committee["index"])
      if att.committee_bits[idx] == 1:
          for val_committee_idx, val_idx in enumerate(committee["validators"]):
              if committee_agg_bits[val_committee_idx] == 1:
                  if is_voting_for_correct_head:
                      attesting_client_unique_attesters_correct_head[get_client_for_validator_idx(int(val_idx))].add(val_idx)

Data related to attestations voting for the previous slot only - the most recently made attestations

Number of attestations for previous slot included in block

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]         1.17 /            3 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.LIGHTHOUSE   : [681]         4.67 /            8 / ['20%: 3.0', '40%: 4.0', '60%: 5.0', '80%: 6.0']  
Client.LODESTAR     : [732]         2.99 /            6 / ['20%: 3.0', '40%: 3.0', '60%: 3.0', '80%: 3.0']  
Client.NIMBUS       : [748]         0.66 /            2 / ['20%: 0.0', '40%: 0.0', '60%: 1.0', '80%: 1.0']  
Client.PRYSM        : [770]         3.08 /            8 / ['20%: 2.0', '40%: 3.0', '60%: 3.0', '80%: 4.0']  
Client.TEKU         : [789]         2.74 /            8 / ['20%: 2.0', '40%: 3.0', '60%: 3.0', '80%: 3.0']  
Client.UNKNOWN      : [10276]       3.19 /            8 / ['20%: 2.0', '40%: 3.0', '60%: 3.0', '80%: 5.0']     

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]         1.50 /            3 / ['20%: 1.0', '40%: 1.0', '60%: 2.0', '80%: 2.0']  
Client.LIGHTHOUSE   :  [127]         3.95 /            8 / ['20%: 2.0', '40%: 3.0', '60%: 5.0', '80%: 6.0']  
Client.LODESTAR     :  [136]         1.83 /            4 / ['20%: 1.0', '40%: 2.0', '60%: 2.0', '80%: 2.0']  
Client.NIMBUS       :  [155]         1.05 /            2 / ['20%: 1.0', '40%: 1.0', '60%: 1.0', '80%: 1.0']  
Client.PRYSM        :  [156]         2.34 /            5 / ['20%: 2.0', '40%: 2.0', '60%: 2.0', '80%: 3.0']  
Client.TEKU         :  [131]         1.85 /            5 / ['20%: 1.0', '40%: 2.0', '60%: 2.0', '80%: 2.0']  
Client.UNKNOWN      : [2248]         2.22 /            8 / ['20%: 1.0', '40%: 2.0', '60%: 2.0', '80%: 3.0']  
Code
len(a for a in block.message.body.attestations if a.data.slot == slot - 1)
Highest number of aggregation bits in an attestation voting for the previous slot

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]    25,257.84 /       31,688 / ['20%: 14,789.0', '40%: 29,469.4', '60%: 30,390.4', '80%: 30,780.4']
Client.LIGHTHOUSE   : [681]    29,903.80 /       31,436 / ['20%: 29,117.8', '40%: 29,981.8', '60%: 30,356.0', '80%: 30,670.2']
Client.LODESTAR     : [732]    25,324.02 /       29,436 / ['20%: 23,907.6', '40%: 25,371.2', '60%: 26,070.4', '80%: 26,978.8']
Client.NIMBUS       : [748]    14,266.82 /       31,291 / ['20%:      0.0', '40%:      0.0', '60%: 28,470.2', '80%: 30,177.4']
Client.PRYSM        : [770]    29,883.16 /       31,579 / ['20%: 28,777.8', '40%: 29,969.8', '60%: 30,434.2', '80%: 30,709.8']
Client.TEKU         : [789]    27,861.01 /       31,115 / ['20%: 28,146.0', '40%: 29,305.0', '60%: 29,771.0', '80%: 30,165.0']
Client.UNKNOWN      : [10276]  28,785.46 /       32,179 / ['20%: 28,740.0', '40%: 29,942.8', '60%: 30,441.0', '80%: 30,820.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]    33,670.28 /       33,999 / ['20%: 33,423.2', '40%: 33,765.8', '60%: 33,880.0', '80%: 33,915.0']
Client.LIGHTHOUSE   : [127]    33,569.65 /       33,903 / ['20%: 33,346.2', '40%: 33,649.0', '60%: 33,751.0', '80%: 33,795.4']
Client.LODESTAR     : [136]    33,311.45 /       33,763 / ['20%: 33,138.2', '40%: 33,446.2', '60%: 33,574.2', '80%: 33,636.6']
Client.NIMBUS       : [155]    31,907.81 /       33,850 / ['20%: 33,164.4', '40%: 33,511.2', '60%: 33,588.0', '80%: 33,683.0']
Client.PRYSM        : [156]    33,416.41 /       33,865 / ['20%: 33,407.4', '40%: 33,614.0', '60%: 33,675.6', '80%: 33,729.8']
Client.TEKU         : [131]    31,714.07 /       33,795 / ['20%: 33,054.4', '40%: 33,441.0', '60%: 33,558.4', '80%: 33,632.0']
Client.UNKNOWN      : [2248]    33,079.87 /       34,064 / ['20%: 33,317.0', '40%: 33,540.6', '60%: 33,643.0', '80%: 33,739.0']
Code
max(sum(att.aggregation_bits) for att in attestations_for_prev_slot)
Highest number of committee bits in an attestation voting for the previous slot

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]        63.55 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.LIGHTHOUSE   : [681]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.LODESTAR     : [732]        63.72 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.NIMBUS       : [748]        30.94 /           64 / ['20%:  0.0', '40%:  0.0', '60%: 64.0', '80%: 64.0']
Client.PRYSM        : [770]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.TEKU         : [789]        61.19 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.UNKNOWN      : [10276]      61.62 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.LIGHTHOUSE   :  [127]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.LODESTAR     :  [136]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.NIMBUS       :  [155]        61.11 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.PRYSM        :  [156]        64.00 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.TEKU         :  [131]        61.36 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Client.UNKNOWN      : [2248]        63.49 /           64 / ['20%: 64.0', '40%: 64.0', '60%: 64.0', '80%: 64.0']
Code
max(sum(att.committee_bits) for att in attestations_for_prev_slot)
Number of unique attesters voting for the previous slot whose attestation was included in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]    25,324.07 /       31,688 / ['20%: 14,805.8', '40%: 29,531.8', '60%: 30,443.8', '80%: 30,812.6']
Client.LIGHTHOUSE   : [681]    29,990.20 /       31,483 / ['20%: 29,182.2', '40%: 30,057.6', '60%: 30,406.0', '80%: 30,719.0']
Client.LODESTAR     : [732]    29,358.46 /       31,091 / ['20%: 28,528.2', '40%: 29,608.0', '60%: 29,949.8', '80%: 30,311.2']
Client.NIMBUS       : [748]    14,272.19 /       31,291 / ['20%:      0.0', '40%:      0.0', '60%: 28,470.2', '80%: 30,177.4']
Client.PRYSM        : [770]    30,299.20 /       31,895 / ['20%: 29,102.6', '40%: 30,406.8', '60%: 30,788.4', '80%: 31,026.4']
Client.TEKU         : [789]    28,027.03 /       31,135 / ['20%: 28,265.0', '40%: 29,397.0', '60%: 29,853.0', '80%: 30,219.0']
Client.UNKNOWN      : [10276]  28,955.52 /       32,388 / ['20%: 28,874.0', '40%: 30,036.0', '60%: 30,517.0', '80%: 30,918.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]    33,769.94 /       33,999 / ['20%: 33,669.4', '40%: 33,837.6', '60%: 33,888.4', '80%: 33,916.4']
Client.LIGHTHOUSE   :  [127]    33,601.24 /       33,916 / ['20%: 33,432.2', '40%: 33,672.8', '60%: 33,769.6', '80%: 33,813.0']
Client.LODESTAR     :  [136]    33,346.81 /       33,763 / ['20%: 33,158.4', '40%: 33,453.4', '60%: 33,581.8', '80%: 33,642.0']
Client.NIMBUS       :  [155]    31,910.50 /       33,850 / ['20%: 33,166.4', '40%: 33,511.2', '60%: 33,588.0', '80%: 33,683.0']
Client.PRYSM        :  [156]    33,894.15 /       34,063 / ['20%: 33,887.4', '40%: 33,944.2', '60%: 33,977.2', '80%: 34,001.6']
Client.TEKU         :  [131]    31,736.89 /       33,797 / ['20%: 33,062.6', '40%: 33,462.0', '60%: 33,564.0', '80%: 33,640.6']
Client.UNKNOWN      : [2248]    33,326.06 /       34,075 / ['20%: 33,439.0', '40%: 33,603.6', '60%: 33,757.0', '80%: 33,961.2']
Code
unique_attesters_for_prev_slot = set()

for att in block.message.body.attestations:
    if att.data.slot != slot - 1:
      continue

    commmitees = await get_committee(state_id=att.data.slot)

    agg_bits_offset = 0

    for committee in commmitees:
        idx = int(committee["index"])
        if att.committee_bits[idx] == 1:
            val_count = len(committee["validators"])
            committee_agg_bits = att.aggregation_bits[
                                 agg_bits_offset:agg_bits_offset + val_count]
            agg_bits_offset += val_count

            for val_committee_idx, val_idx in enumerate(committee["validators"]):
                if committee_agg_bits[val_committee_idx] == 1:
                    unique_attesters_for_prev_slot.add(val_idx)
Number of unique attesters voting for the previous slot + correct target in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]    25,130.34 /       31,688 / ['20%: 14,730.0', '40%: 29,531.8', '60%: 30,443.8', '80%: 30,812.6']
Client.LIGHTHOUSE   : [681]    29,973.88 /       31,483 / ['20%: 29,182.2', '40%: 30,057.6', '60%: 30,406.0', '80%: 30,719.0']
Client.LODESTAR     : [732]    29,358.46 /       31,091 / ['20%: 28,528.2', '40%: 29,608.0', '60%: 29,949.8', '80%: 30,311.2']
Client.NIMBUS       : [748]    14,244.86 /       31,291 / ['20%:      0.0', '40%:      0.0', '60%: 28,470.2', '80%: 30,177.4']
Client.PRYSM        : [770]    30,265.58 /       31,895 / ['20%: 29,059.2', '40%: 30,406.8', '60%: 30,788.4', '80%: 31,026.4']
Client.TEKU         : [789]    28,005.62 /       31,135 / ['20%: 28,265.0', '40%: 29,397.0', '60%: 29,853.0', '80%: 30,219.0']
Client.UNKNOWN      : [10276]  28,927.07 /       32,388 / ['20%: 28,868.4', '40%: 30,036.0', '60%: 30,517.0', '80%: 30,918.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [143]    33,769.94 /       33,999 / ['20%: 33,669.4', '40%: 33,837.6', '60%: 33,888.4', '80%: 33,916.4']
Client.LIGHTHOUSE   : [127]    33,601.24 /       33,916 / ['20%: 33,432.2', '40%: 33,672.8', '60%: 33,769.6', '80%: 33,813.0']
Client.LODESTAR     : [136]    33,136.65 /       33,763 / ['20%: 33,158.4', '40%: 33,453.4', '60%: 33,581.8', '80%: 33,642.0']
Client.NIMBUS       : [155]    31,910.50 /       33,850 / ['20%: 33,166.4', '40%: 33,511.2', '60%: 33,588.0', '80%: 33,683.0']
Client.PRYSM        : [156]    33,805.07 /       34,063 / ['20%: 33,886.4', '40%: 33,940.8', '60%: 33,977.2', '80%: 34,001.6']
Client.TEKU         : [131]    31,736.89 /       33,797 / ['20%: 33,062.6', '40%: 33,462.0', '60%: 33,564.0', '80%: 33,640.6']
Client.UNKNOWN      : [2248]    33,277.04 /       34,075 / ['20%: 33,437.0', '40%: 33,602.6', '60%: 33,756.0', '80%: 33,961.0']
Code
unique_attesters_for_prev_slot_correct_target = set()

for att in block.message.body.attestations:
  if att.data.slot != slot - 1:
    continue

  commmitees = await get_committee(state_id=att.data.slot)

  agg_bits_offset = 0

  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_voting_for_correct_target:
            unique_attesters_for_prev_slot_correct_target.add(val_idx)
Number of unique attesters voting for the previous slot + correct head in block built by client

Epoch range: 2,248 - 2,748

Format: [sample size] mean/max/quantiles

Client.GRANDINE     : [612]    25,035.95 /       31,688 / ['20%: 14,685.6', '40%: 29,495.4', '60%: 30,443.8', '80%: 30,812.6']
Client.LIGHTHOUSE   : [614]    30,149.36 /       31,483 / ['20%: 29,675.0', '40%: 30,189.0', '60%: 30,454.0', '80%: 30,836.0']
Client.LODESTAR     : [670]    29,170.57 /       31,091 / ['20%: 29,037.2', '40%: 29,719.4', '60%: 29,988.0', '80%: 30,340.8']
Client.NIMBUS       : [656]    14,870.08 /       31,291 / ['20%:      0.0', '40%:      0.0', '60%: 29,421.8', '80%: 30,244.6']
Client.PRYSM        : [699]    30,400.53 /       31,890 / ['20%: 29,787.0', '40%: 30,500.0', '60%: 30,824.0', '80%: 31,046.0']
Client.TEKU         : [721]    28,028.10 /       31,135 / ['20%: 28,623.0', '40%: 29,559.0', '60%: 29,906.0', '80%: 30,262.6']
Client.UNKNOWN      : [9329]   28,998.13 /       32,386 / ['20%: 29,407.0', '40%: 30,180.0', '60%: 30,583.0', '80%: 30,963.0']

Epoch range: 8,450 – 8,550

Format: [sample size] mean/max/quantiles

Client.GRANDINE     :  [143]    33,751.57 /       33,999 / ['20%: 33,669.2', '40%: 33,836.6', '60%: 33,888.4', '80%: 33,915.6']
Client.LIGHTHOUSE   :  [127]    33,596.02 /       33,916 / ['20%: 33,390.2', '40%: 33,672.8', '60%: 33,769.6', '80%: 33,812.4']
Client.LODESTAR     :  [136]    33,131.01 /       33,763 / ['20%: 33,158.4', '40%: 33,453.4', '60%: 33,581.0', '80%: 33,642.0']
Client.NIMBUS       :  [155]    31,907.81 /       33,850 / ['20%: 33,164.4', '40%: 33,511.2', '60%: 33,588.0', '80%: 33,683.0']
Client.PRYSM        :  [156]    33,800.87 /       34,063 / ['20%: 33,883.6', '40%: 33,940.0', '60%: 33,977.0', '80%: 34,001.6']
Client.TEKU         :  [131]    31,735.60 /       33,797 / ['20%: 33,062.6', '40%: 33,462.0', '60%: 33,564.0', '80%: 33,640.6']
Client.UNKNOWN      : [2248]    33,271.59 /       34,075 / ['20%: 33,430.6', '40%: 33,599.6', '60%: 33,753.0', '80%: 33,959.2']
Code
unique_attesters_for_prev_slot_correct_head = set()

for att in block.message.body.attestations:
  if att.data.slot != slot - 1:
    continue

  commmitees = await get_committee(state_id=att.data.slot)

  agg_bits_offset = 0

  for committee in commmitees:
    idx = int(committee["index"])
    if att.committee_bits[idx] == 1:
      for val_committee_idx, val_idx in enumerate(committee["validators"]):
        if committee_agg_bits[val_committee_idx] == 1:
          if is_voting_for_correct_head:
            unique_attesters_for_prev_slot_correct_head.add(val_idx)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment