diff --git a/apis/beacon/light_client/bootstrap.yaml b/apis/beacon/light_client/bootstrap.yaml
new file mode 100644
index 00000000..532b5976
--- /dev/null
+++ b/apis/beacon/light_client/bootstrap.yaml
@@ -0,0 +1,54 @@
+get:
+ operationId: getLightClientBootstrap
+ summary: Get `LightClientBootstrap` structure for a requested block root
+ description: |
+ Requests the [`LightClientBootstrap`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#lightclientbootstrap) structure corresponding to a given post-Altair beacon block root.
+ Depending on the `Accept` header it can be returned either as JSON or SSZ-serialized bytes.
+
+ Servers SHOULD provide results as defined in [`create_light_client_bootstrap`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/full-node.md#create_light_client_bootstrap). To fulfill a request, the requested block's post state needs to be known.
+ tags:
+ - Beacon
+ parameters:
+ - name: block_root
+ in: path
+ required: true
+ $ref: '../../../beacon-node-oapi.yaml#/components/parameters/BlockRoot'
+ responses:
+ "200":
+ description: Success
+ headers:
+ Eth-Consensus-Version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/headers/Eth-Consensus-Version'
+ content:
+ application/json:
+ schema:
+ title: GetLightClientBootstrapResponse
+ type: object
+ properties:
+ version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/ConsensusVersion'
+ data:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Altair.LightClientBootstrap'
+ application/octet-stream:
+ schema:
+ description: "SSZ serialized `LightClientBootstrap` bytes. Use Accept header to choose this response type"
+ "400":
+ description: Malformed request parameter
+ content:
+ application/json:
+ schema:
+ $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage"
+ example:
+ code: 400
+ message: "Invalid block root value"
+ "404":
+ description: "`LightClientBootstrap` instance cannot be produced for the given block root"
+ content:
+ application/json:
+ schema:
+ $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage"
+ example:
+ code: 404
+ message: "LC bootstrap unavailable"
+ "500":
+ $ref: "../../../beacon-node-oapi.yaml#/components/responses/InternalError"
diff --git a/apis/beacon/light_client/finality_update.yaml b/apis/beacon/light_client/finality_update.yaml
new file mode 100644
index 00000000..eb8b695d
--- /dev/null
+++ b/apis/beacon/light_client/finality_update.yaml
@@ -0,0 +1,40 @@
+get:
+ operationId: getLightClientFinalityUpdate
+ summary: Get the latest known `LightClientFinalityUpdate`
+ description: |
+ Requests the latest [`LightClientFinalityUpdate`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate) known by the server.
+ Depending on the `Accept` header it can be returned either as JSON or SSZ-serialized bytes.
+
+ Servers SHOULD provide results as defined in [`create_light_client_finality_update`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/full-node.md#create_light_client_finality_update).
+ tags:
+ - Beacon
+ responses:
+ "200":
+ description: Success
+ headers:
+ Eth-Consensus-Version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/headers/Eth-Consensus-Version'
+ content:
+ application/json:
+ schema:
+ title: GetLightClientFinalityUpdateResponse
+ type: object
+ properties:
+ version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/ConsensusVersion'
+ data:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Altair.LightClientFinalityUpdate'
+ application/octet-stream:
+ schema:
+ description: "SSZ serialized `LightClientFinalityUpdate` bytes. Use Accept header to choose this response type"
+ "404":
+ description: "No `LightClientFinalityUpdate` is available"
+ content:
+ application/json:
+ schema:
+ $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage"
+ example:
+ code: 404
+ message: "LC finality update unavailable"
+ "500":
+ $ref: "../../../beacon-node-oapi.yaml#/components/responses/InternalError"
diff --git a/apis/beacon/light_client/optimistic_update.yaml b/apis/beacon/light_client/optimistic_update.yaml
new file mode 100644
index 00000000..9cca0812
--- /dev/null
+++ b/apis/beacon/light_client/optimistic_update.yaml
@@ -0,0 +1,40 @@
+get:
+ operationId: getLightClientOptimisticUpdate
+ summary: Get the latest known `LightClientOptimisticUpdate`
+ description: |
+ Requests the latest [`LightClientOptimisticUpdate`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate) known by the server.
+ Depending on the `Accept` header it can be returned either as JSON or SSZ-serialized bytes.
+
+ Servers SHOULD provide results as defined in [`create_light_client_optimistic_update`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/full-node.md#create_light_client_optimistic_update).
+ tags:
+ - Beacon
+ responses:
+ "200":
+ description: Success
+ headers:
+ Eth-Consensus-Version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/headers/Eth-Consensus-Version'
+ content:
+ application/json:
+ schema:
+ title: GetLightClientOptimisticUpdateResponse
+ type: object
+ properties:
+ version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/ConsensusVersion'
+ data:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Altair.LightClientOptimisticUpdate'
+ application/octet-stream:
+ schema:
+ description: "SSZ serialized `LightClientOptimisticUpdate` bytes. Use Accept header to choose this response type"
+ "404":
+ description: "No `LightClientOptimisticUpdate` is available"
+ content:
+ application/json:
+ schema:
+ $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage"
+ example:
+ code: 404
+ message: "LC optimistic update unavailable"
+ "500":
+ $ref: "../../../beacon-node-oapi.yaml#/components/responses/InternalError"
diff --git a/apis/beacon/light_client/updates.yaml b/apis/beacon/light_client/updates.yaml
new file mode 100644
index 00000000..e82624a8
--- /dev/null
+++ b/apis/beacon/light_client/updates.yaml
@@ -0,0 +1,84 @@
+get:
+ operationId: getLightClientUpdatesByRange
+ summary: Get `LightClientUpdate` instances in a requested sync committee period range
+ description: |
+ Requests the [`LightClientUpdate`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#lightclientupdate) instances in the sync committee period range `[start_period, start_period + count)`, leading up to the current head sync committee period as selected by fork choice.
+ Depending on the `Accept` header they can be returned either as JSON or SSZ-serialized bytes.
+
+ Servers SHOULD provide results as defined in [`create_light_client_update`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/full-node.md#create_light_client_update). They MUST respond with at least the earliest known result within the requested range, and MUST send results in consecutive order (by period). The response MUST NOT contain more than [`min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, count)`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/p2p-interface.md#configuration) results.
+ tags:
+ - Beacon
+ parameters:
+ - name: start_period
+ in: query
+ required: true
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Uint64'
+ - name: count
+ in: query
+ required: true
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Uint64'
+ responses:
+ "200":
+ description: Success
+ content:
+ application/json:
+ schema:
+ title: GetLightClientUpdatesByRangeResponse
+ type: array
+ items:
+ type: object
+ properties:
+ version:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/ConsensusVersion'
+ data:
+ $ref: '../../../beacon-node-oapi.yaml#/components/schemas/Altair.LightClientUpdate'
+ application/octet-stream:
+ schema:
+ description: |
+ Sequence of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `LightClientUpdate` payload:
+ ```
+ (
+ response_chunk_len: Little-endian Uint64 byte length of `response_chunk`
+ response_chunk: (
+ context: 4 byte `ForkDigest`
+ payload: SSZ serialized payload bytes
+ )
+ )
+ ```
+ Use Accept header to choose this response type
+
+ For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `update.sync_aggregate`, which is based on `update.signature_slot`.
+
+ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`:
+
+ | `fork_version` | Response chunk SSZ type |
+ | -------------------------------------------- | ------------------------------------ |
+ | `GENESIS_FORK_VERSION` | n/a |
+ | `ALTAIR_FORK_VERSION` and later | `altair.LightClientUpdate` |
+
+ "400":
+ description: Malformed or missing request parameter
+ content:
+ application/json:
+ schema:
+ $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage"
+ examples:
+ InvalidSyncPeriod:
+ value:
+ code: 400
+ message: "Invalid sync committee period requested"
+ InvalidCount:
+ value:
+ code: 400
+ message: "Invalid count requested"
+ MissingStartPeriodValue:
+ value:
+ code: 400
+ message: "Missing `start_period` value"
+ MissingCountValue:
+ value:
+ code: 400
+ message: "Missing `count` value"
+
+ "500":
+ $ref: "../../../beacon-node-oapi.yaml#/components/responses/InternalError"
diff --git a/apis/eventstream/index.yaml b/apis/eventstream/index.yaml
index 8ed40e36..8a929d3f 100644
--- a/apis/eventstream/index.yaml
+++ b/apis/eventstream/index.yaml
@@ -29,6 +29,8 @@ get:
- finalized_checkpoint
- chain_reorg
- contribution_and_proof
+ - light_client_finality_update
+ - light_client_optimistic_update
responses:
"200":
description: Opened SSE stream.
@@ -73,6 +75,16 @@ get:
value: |
event: contribution_and_proof
data: {"message": {"aggregator_index": "997", "contribution": {"slot": "168097", "beacon_block_root": "0x56f1fd4262c08fa81e27621c370e187e621a67fc80fe42340b07519f84b42ea1", "subcommittee_index": "0", "aggregation_bits": "0xffffffffffffffffffffffffffffffff", "signature": "0x85ab9018e14963026476fdf784cc674da144b3dbdb47516185438768774f077d882087b90ad642469902e782a8b43eed0cfc1b862aa9a473b54c98d860424a702297b4b648f3f30bdaae8a8b7627d10d04cb96a2cc8376af3e54a9aa0c8145e3"}, "selection_proof": "0x87c305f04bfe5db27c2b19fc23e00d7ac496ec7d3e759cbfdd1035cb8cf6caaa17a36a95a08ba78c282725e7b66a76820ca4eb333822bd399ceeb9807a0f2926c67ce67cfe06a0b0006838203b493505a8457eb79913ce1a3bcd1cc8e4ef30ed"}, "signature": "0xac118511474a94f857300b315c50585c32a713e4452e26a6bb98cdb619936370f126ed3b6bb64469259ee92e69791d9e12d324ce6fd90081680ce72f39d85d50b0ff977260a8667465e613362c6d6e6e745e1f9323ec1d6f16041c4e358839ac"}
+ light_client_finality_update:
+ description: The node's latest known `LightClientFinalityUpdate` has been updated
+ value: |
+ event: light_client_finality_update
+ data: {"version":"phase0", "data": {"attested_header": {"slot":"1", "proposer_index":"1", "parent_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "state_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "body_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, "finalized_header": {"slot":"1", "proposer_index":"1", "parent_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "state_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "body_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, "finality_branch": ["0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"], "sync_aggregate": {"sync_committee_bits":"0x01", "sync_committee_signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}, "signature_slot":"1"}}
+ light_client_optimistic_update:
+ description: The node's latest known `LightClientOptimisticUpdate` has been updated
+ value: |
+ event: light_client_optimimstic_update
+ data: {"version":"phase0", "data": {"attested_header": {"slot":"1", "proposer_index":"1", "parent_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "state_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "body_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, "sync_aggregate": {"sync_committee_bits":"0x01", "sync_committee_signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}, "signature_slot":"1"}}
"400":
description: "The topics supplied could not be parsed"
content:
diff --git a/beacon-node-oapi.yaml b/beacon-node-oapi.yaml
index 97792ead..e38ef4d7 100644
--- a/beacon-node-oapi.yaml
+++ b/beacon-node-oapi.yaml
@@ -88,7 +88,14 @@ paths:
$ref: "./apis/beacon/blocks/root.yaml"
/eth/v1/beacon/blocks/{block_id}/attestations:
$ref: "./apis/beacon/blocks/attestations.yaml"
-
+ /eth/v1/beacon/light_client/bootstrap/{block_root}:
+ $ref: "./apis/beacon/light_client/bootstrap.yaml"
+ /eth/v1/beacon/light_client/updates:
+ $ref: "./apis/beacon/light_client/updates.yaml"
+ /eth/v1/beacon/light_client/finality_update:
+ $ref: "./apis/beacon/light_client/finality_update.yaml"
+ /eth/v1/beacon/light_client/optimistic_update:
+ $ref: "./apis/beacon/light_client/optimistic_update.yaml"
/eth/v1/beacon/pool/attestations:
$ref: "./apis/beacon/pool/attestations.yaml"
/eth/v1/beacon/pool/attester_slashings:
@@ -236,6 +243,14 @@ components:
$ref: './types/http.yaml#/ErrorMessage'
IndexedErrorMessage:
$ref: './types/http.yaml#/IndexedErrorMessage'
+ Altair.LightClientBootstrap:
+ $ref: './types/altair/light_client.yaml#/Altair/LightClientBootstrap'
+ Altair.LightClientUpdate:
+ $ref: './types/altair/light_client.yaml#/Altair/LightClientUpdate'
+ Altair.LightClientFinalityUpdate:
+ $ref: './types/altair/light_client.yaml#/Altair/LightClientFinalityUpdate'
+ Altair.LightClientOptimisticUpdate:
+ $ref: './types/altair/light_client.yaml#/Altair/LightClientOptimisticUpdate'
Altair.SignedBeaconBlock:
$ref: './types/altair/block.yaml#/Altair/SignedBeaconBlock'
Altair.BeaconBlock:
@@ -277,6 +292,8 @@ components:
$ref: './params/index.yaml#/StateId'
BlockId:
$ref: './params/index.yaml#/BlockId'
+ BlockRoot:
+ $ref: './params/index.yaml#/BlockRoot'
responses:
InvalidRequest:
diff --git a/params/index.yaml b/params/index.yaml
index 9d04ee48..04751dcc 100644
--- a/params/index.yaml
+++ b/params/index.yaml
@@ -18,3 +18,8 @@ BlockId:
description: |
Block identifier.
Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \, \.
+BlockRoot:
+ $ref: "../types/primitive.yaml#/Root"
+ description: |
+ Block root.
+ \.
diff --git a/types/altair/light_client.yaml b/types/altair/light_client.yaml
new file mode 100644
index 00000000..4586a92d
--- /dev/null
+++ b/types/altair/light_client.yaml
@@ -0,0 +1,71 @@
+Altair:
+ FinalityBranch:
+ type: array
+ items:
+ $ref: '../primitive.yaml#/Root'
+ description: "Merkle proof consisting of [`log2trunc(FINALIZED_ROOT_INDEX])`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#constants) roots"
+ minItems: 6
+ maxItems: 6
+ CurrentSyncCommitteeBranch:
+ type: array
+ items:
+ $ref: '../primitive.yaml#/Root'
+ description: "Merkle proof consisting of [`log2trunc(CURRENT_SYNC_COMMITTEE_INDEX])`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#constants) roots"
+ minItems: 5
+ maxItems: 5
+ NextSyncCommitteeBranch:
+ type: array
+ items:
+ $ref: '../primitive.yaml#/Root'
+ description: "Merkle proof consisting of [`log2trunc(NEXT_SYNC_COMMITTEE_INDEX])`](https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/sync-protocol.md#constants) roots"
+ minItems: 5
+ maxItems: 5
+
+ LightClientBootstrap:
+ type: object
+ properties:
+ header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ current_sync_committee:
+ $ref: './sync_committee.yaml#/Altair/SyncCommittee'
+ current_sync_committee_branch:
+ $ref: '#/Altair/CurrentSyncCommitteeBranch'
+ LightClientUpdate:
+ type: object
+ properties:
+ attested_header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ next_sync_committee:
+ $ref: './sync_committee.yaml#/Altair/SyncCommittee'
+ next_sync_committee_branch:
+ $ref: '#/Altair/NextSyncCommitteeBranch'
+ finalized_header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ finality_branch:
+ $ref: '#/Altair/FinalityBranch'
+ sync_aggregate:
+ $ref: './sync_aggregate.yaml#/Altair/SyncAggregate'
+ signature_slot:
+ $ref: '../primitive.yaml#/Uint64'
+ LightClientFinalityUpdate:
+ type: object
+ properties:
+ attested_header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ finalized_header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ finality_branch:
+ $ref: '#/Altair/FinalityBranch'
+ sync_aggregate:
+ $ref: './sync_aggregate.yaml#/Altair/SyncAggregate'
+ signature_slot:
+ $ref: '../primitive.yaml#/Uint64'
+ LightClientOptimisticUpdate:
+ type: object
+ properties:
+ attested_header:
+ $ref: '../block.yaml#/BeaconBlockHeader'
+ sync_aggregate:
+ $ref: './sync_aggregate.yaml#/Altair/SyncAggregate'
+ signature_slot:
+ $ref: '../primitive.yaml#/Uint64'