Pass blocks to LC data creation functions

Future light client protocol extensions may include data from the block
in addition to data from the state, e.g., `ExecutionPayloadHeader`.
To prepare for this, also pass the block to the corresponding functions.
In practice, blocks access is easier than historic state access, meaning
there are no practical limitations due to this change.
This commit is contained in:
Etan Kissling 2022-10-28 22:14:25 +02:00
parent bab01d6e99
commit ff0e525ecc
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
4 changed files with 113 additions and 90 deletions

View File

@ -40,10 +40,19 @@ Full nodes are expected to derive light client data from historic blocks and sta
### `create_light_client_bootstrap`
To form a `LightClientBootstrap`, the following objects are needed:
- `state`: the post state of any post-Altair block
- `block`: the corresponding block
```python
def create_light_client_bootstrap(state: BeaconState) -> LightClientBootstrap:
def create_light_client_bootstrap(state: BeaconState,
block: SignedBeaconBlock) -> LightClientBootstrap:
assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
assert state.slot == state.latest_block_header.slot
header = state.latest_block_header.copy()
header.state_root = hash_tree_root(state)
assert hash_tree_root(header) == hash_tree_root(block.message)
return LightClientBootstrap(
header=BeaconBlockHeader(
@ -54,7 +63,7 @@ def create_light_client_bootstrap(state: BeaconState) -> LightClientBootstrap:
body_root=state.latest_block_header.body_root,
),
current_sync_committee=state.current_sync_committee,
current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX)
current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX),
)
```
@ -69,13 +78,15 @@ Blocks are considered to be epoch boundary blocks if their block root can occur
To form a `LightClientUpdate`, the following historical states and blocks are needed:
- `state`: the post state of any block with a post-Altair parent block
- `block`: the corresponding block
- `attested_state`: the post state of the block referred to by `block.parent_root`
- `attested_state`: the post state of `attested_block`
- `attested_block`: the block referred to by `block.parent_root`
- `finalized_block`: the block referred to by `attested_state.finalized_checkpoint.root`, if locally available (may be unavailable, e.g., when using checkpoint sync, or if it was pruned locally)
```python
def create_light_client_update(state: BeaconState,
block: SignedBeaconBlock,
attested_state: BeaconState,
attested_block: SignedBeaconBlock,
finalized_block: Optional[SignedBeaconBlock]) -> LightClientUpdate:
assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
@ -89,8 +100,8 @@ def create_light_client_update(state: BeaconState,
assert attested_state.slot == attested_state.latest_block_header.slot
attested_header = attested_state.latest_block_header.copy()
attested_header.state_root = hash_tree_root(attested_state)
assert hash_tree_root(attested_header) == block.message.parent_root
update_attested_period = compute_sync_committee_period_at_slot(attested_header.slot)
assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root
update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot)
# `next_sync_committee` is only useful if the message is signed by the current sync committee
if update_attested_period == update_signature_period:

View File

@ -116,7 +116,7 @@ Requests the `LightClientBootstrap` structure corresponding to a given post-Alta
The request MUST be encoded as an SSZ-field.
Peers SHOULD provide results as defined in [`create_light_client_bootstrap`](./full-node.md#create_light_client_bootstrap). To fulfill a request, the requested block's post state needs to be known.
Peers SHOULD provide results as defined in [`create_light_client_bootstrap`](./full-node.md#create_light_client_bootstrap). To fulfill a request, the requested block and its post state need to be known.
When a `LightClientBootstrap` instance cannot be produced for a given block root, peers SHOULD respond with error code `3: ResourceUnavailable`.

View File

@ -35,7 +35,7 @@ def setup_test(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2 - 1)
trusted_block = state_transition_with_full_block(spec, state, True, True)
trusted_block_root = trusted_block.message.hash_tree_root()
bootstrap = spec.create_light_client_bootstrap(state)
bootstrap = spec.create_light_client_bootstrap(state, trusted_block)
yield "trusted_block_root", "meta", "0x" + trusted_block_root.hex()
yield "bootstrap", bootstrap
test.store = spec.initialize_light_client_store(trusted_block_root, bootstrap)
@ -85,9 +85,9 @@ def emit_force_update(test, spec, state):
})
def emit_update(test, spec, state, block, attested_state, finalized_block, with_next_sync_committee=True):
update = spec.create_light_client_update(state, block, attested_state, finalized_block)
if not with_next_sync_committee:
def emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=True):
update = spec.create_light_client_update(state, block, attested_state, attested_block, finalized_block)
if not with_next:
update.next_sync_committee = spec.SyncCommittee()
update.next_sync_committee_branch = \
[spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))]
@ -135,11 +135,12 @@ def test_light_client_sync(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH - 1)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -160,11 +161,12 @@ def test_light_client_sync(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH - 1)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -184,12 +186,13 @@ def test_light_client_sync(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH - 2)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
transition_to(spec, state, compute_start_slot_at_next_sync_committee_period(spec, state))
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -206,10 +209,11 @@ def test_light_client_sync(spec, state):
# sync committee
# period boundary
# ```
attested_block = block.copy()
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
update = yield from emit_update(test, spec, state, block, attested_state, finalized_block=None)
update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update == update
@ -226,11 +230,12 @@ def test_light_client_sync(spec, state):
# sync committee
# period boundary
# ```
attested_block = block.copy()
attested_state = state.copy()
store_state = attested_state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
update = yield from emit_update(test, spec, state, block, attested_state, finalized_block)
update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update == update
@ -247,6 +252,7 @@ def test_light_client_sync(spec, state):
# sync committee `--- store.finalized_header
# period boundary
# ```
attested_block = block.copy()
attested_state = state.copy()
next_slots(spec, state, spec.UPDATE_TIMEOUT - 1)
yield from emit_force_update(test, spec, state)
@ -268,7 +274,7 @@ def test_light_client_sync(spec, state):
# ```
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
update = yield from emit_update(test, spec, state, block, attested_state, finalized_block=None)
update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None)
assert test.store.finalized_header.slot == store_state.slot
assert test.store.next_sync_committee == store_state.next_sync_committee
assert test.store.best_valid_update == update
@ -285,10 +291,11 @@ def test_light_client_sync(spec, state):
# sync committee sync committee
# period boundary period boundary
# ```
attested_block = block.copy()
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
update = yield from emit_update(test, spec, state, block, attested_state, finalized_block)
update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == store_state.slot
assert test.store.next_sync_committee == store_state.next_sync_committee
assert test.store.best_valid_update == update
@ -314,11 +321,12 @@ def test_light_client_sync(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH - 1)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -336,7 +344,8 @@ def test_supply_sync_committee_from_past_update(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2 - 1)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
@ -347,7 +356,7 @@ def test_supply_sync_committee_from_past_update(spec, state):
assert not spec.is_next_sync_committee_known(test.store)
# Apply `LightClientUpdate` from the past, populating `store.next_sync_committee`
yield from emit_update(test, spec, past_state, block, attested_state, finalized_block)
yield from emit_update(test, spec, past_state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -368,11 +377,12 @@ def test_advance_finality_without_sync_committee(spec, state):
next_slots(spec, state, spec.SLOTS_PER_EPOCH - 1)
finalized_block = state_transition_with_full_block(spec, state, True, True)
finalized_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None
@ -386,11 +396,12 @@ def test_advance_finality_without_sync_committee(spec, state):
_, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 1, True, True)
justified_block = state_transition_with_full_block(spec, state, True, True)
justified_state = state.copy()
_, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH, True, True)
_, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 1, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
yield from emit_update(test, spec, state, block, attested_state, finalized_block, with_next_sync_committee=False)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False)
assert test.store.finalized_header.slot == finalized_state.slot
assert not spec.is_next_sync_committee_known(test.store)
assert test.store.best_valid_update is None
@ -400,27 +411,28 @@ def test_advance_finality_without_sync_committee(spec, state):
past_state = finalized_state
finalized_block = justified_block
finalized_state = justified_state
_, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 1, True, True)
_, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 2, True, True)
attested_block = state_transition_with_full_block(spec, state, True, True)
attested_state = state.copy()
sync_aggregate, _ = get_sync_aggregate(spec, state)
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
# Apply `LightClientUpdate` without `finalized_header` nor `next_sync_committee`
update = yield from emit_update(test, spec, state, block, attested_state, None, with_next_sync_committee=False)
update = yield from emit_update(test, spec, state, block, attested_state, attested_block, None, with_next=False)
assert test.store.finalized_header.slot == past_state.slot
assert not spec.is_next_sync_committee_known(test.store)
assert test.store.best_valid_update == update
assert test.store.optimistic_header.slot == attested_state.slot
# Apply `LightClientUpdate` with `finalized_header` but no `next_sync_committee`
yield from emit_update(test, spec, state, block, attested_state, finalized_block, with_next_sync_committee=False)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False)
assert test.store.finalized_header.slot == finalized_state.slot
assert not spec.is_next_sync_committee_known(test.store)
assert test.store.best_valid_update is None
assert test.store.optimistic_header.slot == attested_state.slot
# Apply full `LightClientUpdate`, supplying `next_sync_committee`
yield from emit_update(test, spec, state, block, attested_state, finalized_block)
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block)
assert test.store.finalized_header.slot == finalized_state.slot
assert test.store.next_sync_committee == finalized_state.next_sync_committee
assert test.store.best_valid_update is None

View File

@ -18,13 +18,13 @@ from eth2spec.test.helpers.state import (
from math import floor
def create_update(spec, test, with_next_sync_committee, with_finality, participation_rate):
def create_update(spec, test, with_next, with_finality, participation_rate):
attested_state, attested_block, finalized_block = test
num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate)
attested_header = signed_block_to_header(spec, attested_block)
if with_next_sync_committee:
if with_next:
next_sync_committee = attested_state.next_sync_committee
next_sync_committee_branch = spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX)
else:
@ -84,76 +84,76 @@ def test_update_ranking(spec, state):
# Create updates (in descending order of quality)
updates = [
# Updates with sync committee finality
create_update(spec, fin, with_next_sync_committee=1, with_finality=1, participation_rate=1.0),
create_update(spec, lat, with_next_sync_committee=1, with_finality=1, participation_rate=1.0),
create_update(spec, fin, with_next_sync_committee=1, with_finality=1, participation_rate=0.8),
create_update(spec, lat, with_next_sync_committee=1, with_finality=1, participation_rate=0.8),
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0),
create_update(spec, lat, with_next=1, with_finality=1, participation_rate=1.0),
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.8),
create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.8),
# Updates without sync committee finality
create_update(spec, att, with_next_sync_committee=1, with_finality=1, participation_rate=1.0),
create_update(spec, att, with_next_sync_committee=1, with_finality=1, participation_rate=0.8),
create_update(spec, att, with_next=1, with_finality=1, participation_rate=1.0),
create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.8),
# Updates without indication of any finality
create_update(spec, att, with_next_sync_committee=1, with_finality=0, participation_rate=1.0),
create_update(spec, fin, with_next_sync_committee=1, with_finality=0, participation_rate=1.0),
create_update(spec, lat, with_next_sync_committee=1, with_finality=0, participation_rate=1.0),
create_update(spec, att, with_next_sync_committee=1, with_finality=0, participation_rate=0.8),
create_update(spec, fin, with_next_sync_committee=1, with_finality=0, participation_rate=0.8),
create_update(spec, lat, with_next_sync_committee=1, with_finality=0, participation_rate=0.8),
create_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0),
create_update(spec, fin, with_next=1, with_finality=0, participation_rate=1.0),
create_update(spec, lat, with_next=1, with_finality=0, participation_rate=1.0),
create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.8),
create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.8),
create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.8),
# Updates with sync committee finality but no `next_sync_committee`
create_update(spec, sig, with_next_sync_committee=0, with_finality=1, participation_rate=1.0),
create_update(spec, fin, with_next_sync_committee=0, with_finality=1, participation_rate=1.0),
create_update(spec, lat, with_next_sync_committee=0, with_finality=1, participation_rate=1.0),
create_update(spec, sig, with_next_sync_committee=0, with_finality=1, participation_rate=0.8),
create_update(spec, fin, with_next_sync_committee=0, with_finality=1, participation_rate=0.8),
create_update(spec, lat, with_next_sync_committee=0, with_finality=1, participation_rate=0.8),
create_update(spec, sig, with_next=0, with_finality=1, participation_rate=1.0),
create_update(spec, fin, with_next=0, with_finality=1, participation_rate=1.0),
create_update(spec, lat, with_next=0, with_finality=1, participation_rate=1.0),
create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.8),
create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.8),
create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.8),
# Updates without sync committee finality and also no `next_sync_committee`
create_update(spec, att, with_next_sync_committee=0, with_finality=1, participation_rate=1.0),
create_update(spec, att, with_next_sync_committee=0, with_finality=1, participation_rate=0.8),
create_update(spec, att, with_next=0, with_finality=1, participation_rate=1.0),
create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.8),
# Updates without indication of any finality nor `next_sync_committee`
create_update(spec, sig, with_next_sync_committee=0, with_finality=0, participation_rate=1.0),
create_update(spec, att, with_next_sync_committee=0, with_finality=0, participation_rate=1.0),
create_update(spec, fin, with_next_sync_committee=0, with_finality=0, participation_rate=1.0),
create_update(spec, lat, with_next_sync_committee=0, with_finality=0, participation_rate=1.0),
create_update(spec, sig, with_next_sync_committee=0, with_finality=0, participation_rate=0.8),
create_update(spec, att, with_next_sync_committee=0, with_finality=0, participation_rate=0.8),
create_update(spec, fin, with_next_sync_committee=0, with_finality=0, participation_rate=0.8),
create_update(spec, lat, with_next_sync_committee=0, with_finality=0, participation_rate=0.8),
create_update(spec, sig, with_next=0, with_finality=0, participation_rate=1.0),
create_update(spec, att, with_next=0, with_finality=0, participation_rate=1.0),
create_update(spec, fin, with_next=0, with_finality=0, participation_rate=1.0),
create_update(spec, lat, with_next=0, with_finality=0, participation_rate=1.0),
create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.8),
create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.8),
create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.8),
create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.8),
# Updates with low sync committee participation
create_update(spec, fin, with_next_sync_committee=1, with_finality=1, participation_rate=0.4),
create_update(spec, lat, with_next_sync_committee=1, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next_sync_committee=1, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next_sync_committee=1, with_finality=0, participation_rate=0.4),
create_update(spec, fin, with_next_sync_committee=1, with_finality=0, participation_rate=0.4),
create_update(spec, lat, with_next_sync_committee=1, with_finality=0, participation_rate=0.4),
create_update(spec, sig, with_next_sync_committee=0, with_finality=1, participation_rate=0.4),
create_update(spec, fin, with_next_sync_committee=0, with_finality=1, participation_rate=0.4),
create_update(spec, lat, with_next_sync_committee=0, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next_sync_committee=0, with_finality=1, participation_rate=0.4),
create_update(spec, sig, with_next_sync_committee=0, with_finality=0, participation_rate=0.4),
create_update(spec, att, with_next_sync_committee=0, with_finality=0, participation_rate=0.4),
create_update(spec, fin, with_next_sync_committee=0, with_finality=0, participation_rate=0.4),
create_update(spec, lat, with_next_sync_committee=0, with_finality=0, participation_rate=0.4),
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4),
create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.4),
create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.4),
create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.4),
create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.4),
create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.4),
create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.4),
create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.4),
create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.4),
create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.4),
create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.4),
create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.4),
# Updates with very low sync committee participation
create_update(spec, fin, with_next_sync_committee=1, with_finality=1, participation_rate=0.2),
create_update(spec, lat, with_next_sync_committee=1, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next_sync_committee=1, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next_sync_committee=1, with_finality=0, participation_rate=0.2),
create_update(spec, fin, with_next_sync_committee=1, with_finality=0, participation_rate=0.2),
create_update(spec, lat, with_next_sync_committee=1, with_finality=0, participation_rate=0.2),
create_update(spec, sig, with_next_sync_committee=0, with_finality=1, participation_rate=0.2),
create_update(spec, fin, with_next_sync_committee=0, with_finality=1, participation_rate=0.2),
create_update(spec, lat, with_next_sync_committee=0, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next_sync_committee=0, with_finality=1, participation_rate=0.2),
create_update(spec, sig, with_next_sync_committee=0, with_finality=0, participation_rate=0.2),
create_update(spec, att, with_next_sync_committee=0, with_finality=0, participation_rate=0.2),
create_update(spec, fin, with_next_sync_committee=0, with_finality=0, participation_rate=0.2),
create_update(spec, lat, with_next_sync_committee=0, with_finality=0, participation_rate=0.2),
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2),
create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.2),
create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.2),
create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.2),
create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.2),
create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.2),
create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.2),
create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.2),
create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.2),
create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.2),
create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.2),
create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.2),
]
yield "updates", updates