Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExecutionPayloadHeader to LC data #3151

Merged
merged 33 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0fb0b26
Add accessors for LC header
etan-status Dec 6, 2022
14fd937
Fix
etan-status Dec 6, 2022
364d106
Merge branch 'sf-epochoverrides' into lc-eph
etan-status Dec 11, 2022
08a2080
Merge branch 'ci-phasesconfig' into lc-eph
etan-status Dec 11, 2022
c1a6b12
Merge branch 'lc-toheader' into lc-eph
etan-status Dec 11, 2022
9ab22b3
Merge branch 'lc-accessors' into lc-eph
etan-status Dec 11, 2022
2e97af2
Add `ExecutionPayloadHeader` to LC data
etan-status Dec 11, 2022
7e6a990
Merge branch 'ci-phasesconfig' into lc-eph
etan-status Dec 12, 2022
2df8a55
Fix LC references in main readme
etan-status Dec 12, 2022
11d2a59
Flip `is_valid_light_client_header` logic for extensibility
etan-status Dec 12, 2022
d6da56c
Remove double mention of validator changes in readme
etan-status Dec 12, 2022
5028a80
Implicit init during fork transition
etan-status Dec 12, 2022
4df8663
Rename `legacy` --> `altair` in test name
etan-status Dec 12, 2022
e67ca3d
Compute epoch only once for better readability
etan-status Dec 12, 2022
8ad6810
EIP4844 support (`excess_data_gas`), fork tests nyi
etan-status Dec 12, 2022
dc05a3f
Rename test back
etan-status Dec 12, 2022
700bef7
Fix `is_valid_light_client_header`
etan-status Dec 12, 2022
a8dabc0
Add `test_eip4844_store_with_legacy_data` (fork test still nyi)
etan-status Dec 12, 2022
af78506
Merge branch 'el-rlp' into lc-eph
etan-status Dec 13, 2022
3bfac0e
Merge branch 'lc-toheader' into lc-eph
etan-status Dec 13, 2022
f24365f
Merge branch 'ci-phasesconfig' into lc-eph
etan-status Dec 13, 2022
02abdc3
Merge branch 'dev' into lc-eph
etan-status Dec 13, 2022
b047151
Merge branch 'dev' into lc-eph
etan-status Jan 3, 2023
e5cda17
Run fork test for EIP4844
etan-status Jan 4, 2023
ce7fd41
Add test for LC data spanning 3 forks
etan-status Jan 4, 2023
3754360
Merge branch 'dev' into lc-eph
etan-status Jan 5, 2023
53a95f0
Merge branch 'dev' into lc-eph
etan-status Jan 10, 2023
82d6267
Merge branch 'dev' into lc-eph
etan-status Jan 12, 2023
b720581
Update sync test documentation
etan-status Jan 12, 2023
ca32fe8
Add docstrings to explain empty header
etan-status Jan 13, 2023
a580f82
Use `beacon` wrapper in `upgrade_lc_header_to_capella`
etan-status Jan 13, 2023
514d443
Use `bellatrix` in `upgrade_x_to_capella` helpers
etan-status Jan 13, 2023
ffd047c
Consistent test step naming
etan-status Jan 14, 2023
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ GENERATOR_VENVS = $(patsubst $(GENERATOR_DIR)/%, $(GENERATOR_DIR)/%venv, $(GENER
MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \
$(wildcard $(SPEC_DIR)/altair/*.md) $(wildcard $(SPEC_DIR)/altair/**/*.md) \
$(wildcard $(SPEC_DIR)/bellatrix/*.md) \
$(wildcard $(SPEC_DIR)/capella/*.md) \
$(wildcard $(SPEC_DIR)/capella/*.md) $(wildcard $(SPEC_DIR)/capella/**/*.md) \
$(wildcard $(SPEC_DIR)/custody/*.md) \
$(wildcard $(SPEC_DIR)/das/*.md) \
$(wildcard $(SPEC_DIR)/sharding/*.md) \
$(wildcard $(SPEC_DIR)/eip4844/*.md) \
$(wildcard $(SPEC_DIR)/eip4844/*.md) $(wildcard $(SPEC_DIR)/eip4844/**/*.md) \
$(wildcard $(SSZ_DIR)/*.md)

COV_HTML_OUT=.htmlcov
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Features are researched and developed in parallel, and then consolidated into se
### In-development Specifications
| Code Name or Topic | Specs | Notes |
| - | - | - |
| Capella (tentative) | <ul><li>Core</li><ul><li>[Beacon chain changes](specs/capella/beacon-chain.md)</li><li>[Capella fork](specs/capella/fork.md)</li></ul><li>Additions</li><ul><li>[Validator additions](specs/capella/validator.md)</li><li>[P2P networking](specs/capella/p2p-interface.md)</li></ul></ul> |
| EIP4844 (tentative) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/eip4844/beacon-chain.md)</li><li>[EIP-4844 fork](specs/eip4844/fork.md)</li><li>[Polynomial commitments](specs/eip4844/polynomial-commitments.md)</li><li>[Fork choice changes](specs/eip4844/fork-choice.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/eip4844/validator.md)</li><li>[P2P networking](specs/eip4844/p2p-interface.md)</li></ul></ul> |
| Capella (tentative) | <ul><li>Core</li><ul><li>[Beacon chain changes](specs/capella/beacon-chain.md)</li><li>[Capella fork](specs/capella/fork.md)</li></ul><li>Additions</li><ul><li>[Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))</li></ul><ul><li>[Validator additions](specs/capella/validator.md)</li><li>[P2P networking](specs/capella/p2p-interface.md)</li></ul></ul> |
| EIP4844 (tentative) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/eip4844/beacon-chain.md)</li><li>[EIP-4844 fork](specs/eip4844/fork.md)</li><li>[Polynomial commitments](specs/eip4844/polynomial-commitments.md)</li><li>[Fork choice changes](specs/eip4844/fork-choice.md)</li></ul><li>Additions</li><ul><li>[Light client sync protocol changes](specs/eip4844/light-client/sync-protocol.md) ([fork](specs/eip4844/light-client/fork.md), [full node](specs/eip4844/light-client/full-node.md), [networking](specs/eip4844/light-client/p2p-interface.md))</li></ul><ul><li>[Honest validator guide changes](specs/eip4844/validator.md)</li><li>[P2P networking](specs/eip4844/p2p-interface.md)</li></ul></ul> |
| Sharding (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/sharding/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[P2P networking](specs/sharding/p2p-interface.md)</li></ul></ul> |
| Custody Game (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/custody_game/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/custody_game/validator.md)</li></ul></ul> | Dependent on sharding |
| Data Availability Sampling (outdated) | <ul><li>Core</li><ul><li>[Core types and functions](specs/das/das-core.md)</li><li>[Fork choice changes](specs/das/fork-choice.md)</li></ul><li>Additions</li><ul><li>[P2P Networking](specs/das/p2p-interface.md)</li><li>[Sampling process](specs/das/sampling.md)</li></ul></ul> | <ul><li> Dependent on sharding</li><li>[Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)</li></ul> |
Expand Down
24 changes: 24 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,21 @@ def imports(cls, preset_name: str):
'''


@classmethod
def sundry_functions(cls) -> str:
return super().sundry_functions() + '\n\n' + '''
def compute_merkle_proof_for_block_body(body: BeaconBlockBody,
index: GeneralizedIndex) -> Sequence[Bytes32]:
return build_proof(body.get_backing(), index)'''


@classmethod
def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
constants = {
'EXECUTION_PAYLOAD_INDEX': 'GeneralizedIndex(25)',
}
return {**super().hardcoded_ssz_dep_constants(), **constants}

#
# EIP4844SpecBuilder
#
Expand Down Expand Up @@ -690,6 +705,7 @@ def format_protocol(protocol_name: str, protocol_def: ProtocolDefinition) -> str
if k in [
"ceillog2",
"floorlog2",
"compute_merkle_proof_for_block_body",
"compute_merkle_proof_for_state",
]:
del spec_object.functions[k]
Expand Down Expand Up @@ -982,6 +998,10 @@ def finalize_options(self):
"""
if self.spec_fork in (CAPELLA, EIP4844):
self.md_doc_paths += """
specs/capella/light-client/fork.md
specs/capella/light-client/full-node.md
specs/capella/light-client/p2p-interface.md
specs/capella/light-client/sync-protocol.md
specs/capella/beacon-chain.md
specs/capella/fork.md
specs/capella/fork-choice.md
Expand All @@ -990,6 +1010,10 @@ def finalize_options(self):
"""
if self.spec_fork == EIP4844:
self.md_doc_paths += """
specs/eip4844/light-client/fork.md
specs/eip4844/light-client/full-node.md
specs/eip4844/light-client/p2p-interface.md
specs/eip4844/light-client/sync-protocol.md
specs/eip4844/beacon-chain.md
specs/eip4844/fork.md
specs/eip4844/fork-choice.md
Expand Down
92 changes: 92 additions & 0 deletions specs/capella/light-client/fork.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Capella Light Client -- Fork Logic

## Table of contents

<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Introduction](#introduction)
- [Upgrading light client data](#upgrading-light-client-data)
- [Upgrading the store](#upgrading-the-store)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Introduction

This document describes how to upgrade existing light client objects based on the [Altair specification](../../altair/light-client/sync-protocol.md) to Capella. This is necessary when processing pre-Capella data with a post-Capella `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.

### Upgrading light client data

A Capella `LightClientStore` can still process earlier light client data. In order to do so, that pre-Capella data needs to be locally upgraded to Capella before processing.

```python
def upgrade_lc_header_to_capella(pre: BeaconBlockHeader) -> LightClientHeader:
return LightClientHeader(
beacon=pre,
)
```

```python
def upgrade_lc_bootstrap_to_capella(pre: altair.LightClientBootstrap) -> LightClientBootstrap:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although altair.LightClientBootstrap SSZ fields are identical bellatrix.LightClientBootstrap, I still think it should be bellatrix.LightClientBootstrap here for the fork transition. That is, we need bellatrix/light-client/fork.md and upgrade_*_to_bellatrix helpers.

Moreover, should we make bellatrix.LightClientHeader include ExecutionPayloadHeader and the Merkle proof? It seems more natural since the ExecutionPayloadHeader field was first introduced in Bellatrix. However, (1) it's less useful since Capella is coming soon, and (2) we are still discussing #3078. So I'd say it's fine to keep bellatrix.LightClientHeader as simple as altair.LightClientHeader.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, not sure about the nop upgrade_*_to_bellatrix — this would then be required for any future fork, regardless of whether there are any real updates.

Kinda like it with altair for readability (in practice, implementations will reuse the Altair definition for Bellatrix and not duplicate all the code with every fork). Agree though, that it is a bit hacky as proposed.

Anyhow, if you insist, can update it (it works well as-is in pytests though).

About changing Bellatrix data: that one is already being cached in DBs and gossiped without the ExecutionPayloadHeader. Changing that would be quite tricky (and in case of gossip may even need a version bump on those topics to avoid disconnecting peers on the previous version). Would therefore leave Bellatrix as is, also considering Capella is in the near future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About upgrade_*_to_bellatrix, those are actually not needed. These upgrade helpers are only used when obtaining Altair formatted data and trying to feed it to an already-upgraded LightClientStore.

In the p2p-interface.md files you can see that it is not possible to obtain a bellatrix.LightClient* object.

fork_version Response chunk SSZ type
GENESIS_FORK_VERSION n/a
ALTAIR_FORK_VERSION through BELLATRIX_FORK_VERSION altair.LightClientUpdate
CAPELLA_FORK_VERSION capella.LightClientUpdate
EIP4844_FORK_VERSION and later eip4844.LightClientUpdate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, with this, it is actually correct to have the upgrade convert directly from altair.LightClient* to capella.LightClient*.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(as in, there is no way to actually obtain a bellatrix.LightClientUpdate in practice, so no upgrade facility is needed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I agree on no need to implement upgrade_*_to_bellatrix and the whole bellatrix/light-client/fork.md file. 👍

But I still think it's good to use the "previous fork" (bellatrix) in upgrade_*_to_capella in specs.

  • In markdown specs, bellatrix.X means the class/method version we have in Bellatrix.
  • In pyspec, we automatically "copy" the code from the previous definition. It's like an inheritance. So bellatrix.LightClientUpdate exists in pyspec usage, although it is just as same as altair.LightClientUpdate definition.
  • If we can always use the "previous fork" in the fork transition specs, I think it would be fewer potential bugs. i.e., we don't have to worry about which fork to use if we have this pattern.

If client implementations actually skip the "unchanged-phase" objects, it's also acceptable since the results are the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, will change the function signature to bellatrix.X but omit the upgrade_*_to_bellatrix stub.

return LightClientBootstrap(
header=upgrade_lc_header_to_capella(pre.header),
current_sync_committee=pre.current_sync_committee,
current_sync_committee_branch=pre.current_sync_committee_branch,
)
```

```python
def upgrade_lc_update_to_capella(pre: altair.LightClientUpdate) -> LightClientUpdate:
return LightClientUpdate(
attested_header=upgrade_lc_header_to_capella(pre.attested_header),
next_sync_committee=pre.next_sync_committee,
next_sync_committee_branch=pre.next_sync_committee_branch,
finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
finality_branch=pre.finality_branch,
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```

```python
def upgrade_lc_finality_update_to_capella(pre: altair.LightClientFinalityUpdate) -> LightClientFinalityUpdate:
return LightClientFinalityUpdate(
attested_header=upgrade_lc_header_to_capella(pre.attested_header),
finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
finality_branch=pre.finality_branch,
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```

```python
def upgrade_lc_optimistic_update_to_capella(pre: altair.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate:
return LightClientOptimisticUpdate(
attested_header=upgrade_lc_header_to_capella(pre.attested_header),
sync_aggregate=pre.sync_aggregate,
signature_slot=pre.signature_slot,
)
```

### Upgrading the store

Existing `LightClientStore` objects based on Altair MUST be upgraded to Capella before Capella based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `CAPELLA_FORK_EPOCH`.

```python
def upgrade_lc_store_to_capella(pre: altair.LightClientStore) -> LightClientStore:
if pre.best_valid_update is None:
best_valid_update = None
else:
best_valid_update = upgrade_lc_update_to_capella(pre.best_valid_update)
return LightClientStore(
finalized_header=upgrade_lc_header_to_capella(pre.finalized_header),
current_sync_committee=pre.current_sync_committee,
next_sync_committee=pre.next_sync_committee,
best_valid_update=best_valid_update,
optimistic_header=upgrade_lc_header_to_capella(pre.optimistic_header),
previous_max_active_participants=pre.previous_max_active_participants,
current_max_active_participants=pre.current_max_active_participants,
)
```
78 changes: 78 additions & 0 deletions specs/capella/light-client/full-node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Capella Light Client -- Full Node

**Notice**: This document is a work-in-progress for researchers and implementers.

## Table of contents

<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Introduction](#introduction)
- [Helper functions](#helper-functions)
- [`compute_merkle_proof_for_block_body`](#compute_merkle_proof_for_block_body)
- [Modified `block_to_light_client_header`](#modified-block_to_light_client_header)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Introduction

This upgrade adds information about the execution payload to light client data as part of the Capella upgrade.

## Helper functions

### `compute_merkle_proof_for_block_body`

```python
def compute_merkle_proof_for_block_body(body: BeaconBlockBody,
index: GeneralizedIndex) -> Sequence[Bytes32]:
...
```

### Modified `block_to_light_client_header`

```python
def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
epoch = compute_epoch_at_slot(block.message.slot)

if epoch >= CAPELLA_FORK_EPOCH:
Comment on lines +36 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it because block could be bellatrix.SignedBeaconBlock here? What do you think about adding a docstring about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly (or, in theory, even all the way back to Altair or Phase0, if bellatrix / altair never finalized, and finalized header is still back in those ancient forks).

Added a comment to clarify that.

payload = block.message.body.execution_payload
execution_header = ExecutionPayloadHeader(
parent_hash=payload.parent_hash,
fee_recipient=payload.fee_recipient,
state_root=payload.state_root,
receipts_root=payload.receipts_root,
logs_bloom=payload.logs_bloom,
prev_randao=payload.prev_randao,
block_number=payload.block_number,
gas_limit=payload.gas_limit,
gas_used=payload.gas_used,
timestamp=payload.timestamp,
extra_data=payload.extra_data,
base_fee_per_gas=payload.base_fee_per_gas,
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals),
)
execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX)
else:
# Note that during fork transitions, `finalized_header` may still point to earlier forks.
# While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`),
# it was not included in the corresponding light client data. To ensure compatibility
# with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data.
execution_header = ExecutionPayloadHeader()
execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]

return LightClientHeader(
beacon=BeaconBlockHeader(
slot=block.message.slot,
proposer_index=block.message.proposer_index,
parent_root=block.message.parent_root,
state_root=block.message.state_root,
body_root=hash_tree_root(block.message.body),
),
execution=execution_header,
execution_branch=execution_branch,
)
```
99 changes: 99 additions & 0 deletions specs/capella/light-client/p2p-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Capella Light Client -- Networking

**Notice**: This document is a work-in-progress for researchers and implementers.

## Table of contents

<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Networking](#networking)
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [`light_client_finality_update`](#light_client_finality_update)
- [`light_client_optimistic_update`](#light_client_optimistic_update)
- [The Req/Resp domain](#the-reqresp-domain)
- [Messages](#messages)
- [GetLightClientBootstrap](#getlightclientbootstrap)
- [LightClientUpdatesByRange](#lightclientupdatesbyrange)
- [GetLightClientFinalityUpdate](#getlightclientfinalityupdate)
- [GetLightClientOptimisticUpdate](#getlightclientoptimisticupdate)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Networking

The [Altair light client networking specification](../../altair/light-client/p2p-interface.md) is extended to exchange [Capella light client data](./sync-protocol.md).

### The gossip domain: gossipsub

#### Topics and messages

##### Global topics

###### `light_client_finality_update`

[0]: # (eth2spec: skip)

| `fork_version` | Message SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientFinalityUpdate` |

###### `light_client_optimistic_update`

[0]: # (eth2spec: skip)

| `fork_version` | Message SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientOptimisticUpdate` |

### The Req/Resp domain

#### Messages

##### GetLightClientBootstrap

[0]: # (eth2spec: skip)

| `fork_version` | Response SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientBootstrap` |

##### LightClientUpdatesByRange

[0]: # (eth2spec: skip)

| `fork_version` | Response chunk SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientUpdate` |

##### GetLightClientFinalityUpdate

[0]: # (eth2spec: skip)

| `fork_version` | Response SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientFinalityUpdate` |

##### GetLightClientOptimisticUpdate

[0]: # (eth2spec: skip)

| `fork_version` | Response SSZ type |
| ------------------------------------------------------ | ------------------------------------- |
| `GENESIS_FORK_VERSION` | n/a |
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
| `CAPELLA_FORK_VERSION` and later | `capella.LightClientOptimisticUpdate` |
Loading