From 1df34ecd8299dce144b4a283aaffdc4c4f2bd4ec Mon Sep 17 00:00:00 2001 From: Ingridmichelledev Date: Thu, 22 Sep 2022 12:19:55 +0200 Subject: [PATCH] Define endpoints for light client sync Introduces additional REST endpoints for light client sync, compatible with the libp2p specification defined in `ethereum/consensus-specs`: https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/altair/light-client/p2p-interface.md Endpoints are defined to be fork-aware to allow potential optimizations such as including EL block hash into `BeaconBlockHeader` in the future. The `getLightClientUpdatesByRange` endpoint is a new kind of endpoint, as it introduces the concept of list responses. Each list item could potentially be of a different fork. Likewise, for the events stream, the fork may update between events. Both the list response and the event are additionall wrapped with a per-item `version` indicator in JSON. For SSZ, the list items are encoded as length/version/payload triples. Note that the events endpoint does not support the SSZ format. This builds on prior work from: - @dapplion at https://github.com/ethereum/beacon-APIs/pull/181 The proof endpoint in that PR is out-of-scope here, but could be useful as part of the debug API as an `eth_getProof` equivalent for CL data. --- apis/beacon/light_client/bootstrap.yaml | 54 ++++++++++++ apis/beacon/light_client/finality_update.yaml | 40 +++++++++ .../light_client/optimistic_update.yaml | 40 +++++++++ apis/beacon/light_client/updates.yaml | 84 +++++++++++++++++++ apis/eventstream/index.yaml | 12 +++ beacon-node-oapi.yaml | 19 ++++- params/index.yaml | 5 ++ types/altair/light_client.yaml | 71 ++++++++++++++++ 8 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 apis/beacon/light_client/bootstrap.yaml create mode 100644 apis/beacon/light_client/finality_update.yaml create mode 100644 apis/beacon/light_client/optimistic_update.yaml create mode 100644 apis/beacon/light_client/updates.yaml create mode 100644 types/altair/light_client.yaml diff --git a/apis/beacon/light_client/bootstrap.yaml b/apis/beacon/light_client/bootstrap.yaml new file mode 100644 index 0000000..532b597 --- /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 0000000..eb8b695 --- /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 0000000..9cca081 --- /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 0000000..e82624a --- /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 8ed40e3..8a929d3 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 97792ea..e38ef4d 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 9d04ee4..04751dc 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 0000000..4586a92 --- /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'