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 lightclient routes #181

Closed
wants to merge 10 commits into from

Conversation

dapplion
Copy link
Collaborator

@dapplion dapplion commented Dec 3, 2021

Adds minimal set of lightclient routes to super a server-based trust-less censorable lightclient.

Sample usage flow for these APIs:

  1. Gather weak subjectivity checkpoint root from some trusted source
  2. Call /eth/v1/lightclient/snapshot/{block_root} to get an initial SyncCommittee
  3. Sync from initial SyncCommittee's sync period to clock sync period with /eth/v1/lightclient/committee_updates
  4. Subscribe to head update events
    4.1. Subscribe to /eth/v1/events?topics=lightclient_head_update
    4.2. If SSE are not available or to get the first head event faster, poll /eth/v1/lightclient/head_update
  5. Once close to the end of the current clock sync period, call /eth/v1/lightclient/committee_updates

For a sample implementation of this routes see:

Live demo: https://lodestar-light-client-demo.netlify.app

@@ -73,6 +74,17 @@ 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"}
lightclient_head_update:
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see a need for _update here; the event is, by definition, an update.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, tho I'm unsure if lightclient_head can also be confusing since you can get multiple events for the same head which is not the same behavior as the head event.

Choose a reason for hiding this comment

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

I think it was called lightlcient_head_update because the data structure emitted is called a LightClientHeadUpdate somewhere.

Similar to the LightClientUpdate in the specs.

Not saying its a great name, just saying..

apis/eventstream/index.yaml Outdated Show resolved Hide resolved
The node has received a new or better lightclient head update. `header` is the block header signed by `sync_aggregate`.
Updates may be collected via
- Next block's syncAggregate field
- Aggregating messages from gossip topic `sync_committee_contribution_and_proof`
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this considered safe, if this information is not yet in a (voted upon) block? Is there any way of knowing the level of finality of the provided head?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is this considered safe, if this information is not yet in a (voted upon) block?

Yes, adding the SyncAggregate is only useful to give on-chain incentives to sync committee members. Gathering the data from gossip topics is identical.

Is there any way of knowing the level of finality of the provided head?

Not really, the main data points lightclients can rely on are:

  • participation of this SyncAggregate
  • if the block is finalized or not

apis/lightclient/committee_updates.yaml Outdated Show resolved Hide resolved
apis/lightclient/head_update.yaml Outdated Show resolved Hide resolved
summary: Get latest best head update
description: |
Returns the latest best head update available. Clients should use the SSE type `lightclient_head_update`
unless to get the very first head update after syncing, or if SSE are not supported by the server.
Copy link
Contributor

Choose a reason for hiding this comment

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

Events are part of the spec so the latter part is not a relevant comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the latter part is not a relevant comment.

Do you refer to the part where SSE may not be supported by the server? At least Lodestar allows to disable the events namespace individually. Also some reverse proxies may not support SSE depending on their buffering configuration.

"200":
description: Success
content:
application/octet-stream:
Copy link
Contributor

Choose a reason for hiding this comment

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

There should be a JSON response here as well. This will also give a location to explain the structure of the multiproof.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The JSON representation of this format is widely inefficient. Since JSON is the default I'll argue into only offering application/octet-stream to force consumers to use the efficient path

apis/lightclient/snapshot.yaml Outdated Show resolved Hide resolved
@@ -96,6 +98,15 @@ paths:
/eth/v1/debug/beacon/heads:
$ref: './apis/debug/heads.yaml'

/eth/v1/lightclient/committee_updates:
Copy link
Contributor

Choose a reason for hiding this comment

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

The API has historically defined committee as a beacon committee, and sync_committee as a sync committee, so I believe you want the latter here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Even if it's scoped in the lightclient namespace is there a risk of confusion?

Choose a reason for hiding this comment

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

I support using sync_committee for clarity here.

@arnetheduck
Copy link
Contributor

This is great as a draft, but believe it's good to settle on a p2p protocol before enshrining / merging it such that implementations don't have to maintain two views of the same data that are slightly different - this work has started in ethereum/consensus-specs#2267 and should be completed first - we are in the process of implementing it and will be providing updates soon.

The long-term idea here would be that beacon nodes serve light client data via p2p just like they serve blocks which enables a very fast consensus sync in general and where serving the data would be part of the standard feature set offered by clients via P2P (to later be mirrored in the REST API).

@mcdee
Copy link
Contributor

mcdee commented Dec 4, 2021

A few generic questions:

  • should /eth/v1/lightclient/snapshot/ only take a block root, or should it allow the more generic block ID? Rationale behind this would be to allow simple retrieval of the snapshot from a node which is considered trusted.
  • how should a client obtain the period(s) in step 3 given the data obtained so far? Seems like they need the spec to be able to go from slot to sync committee period, but should this be trusted? Would it make sense to use slots here for the from and to parameters, and have the beacon node translate them to sync committee periods?
  • for 5) how does the client know when the sync period is coming up for a change? Perhaps a slots_until_next_sync_committee_period or similar should be added to the snapshot information?

@dapplion
Copy link
Collaborator Author

dapplion commented Dec 5, 2021

RE @mcdee

should /eth/v1/lightclient/snapshot/ only take a block root, or should it allow the more generic block ID? Rationale behind this would be to allow simple retrieval of the snapshot from a node which is considered trusted.

Good point! Tho at least one block ID value is not suitable "genesis". Also if you use head you will have to guess the block_root if you want to validate the merkle proof. If you want a SyncCommittee trusting the node you can just query /eth/v1/beacon/states/{state_id}/sync_committees and /eth/v1/beacon/headers/{block_id}

how should a client obtain the period(s) in step 3 given the data obtained so far? Seems like they need the spec to be able to go from slot to sync committee period, but should this be trusted? Would it make sense to use slots here for the from and to parameters, and have the beacon node translate them to sync committee periods?

The config, genesis_time and genesis_validators_root of the network should be known ahead of time by the lightclient consumer. Then you can compute sync periods from slots. Using sync periods allows to put a cache layer in front of the node to speed up responses. If using slots, the same response can be requested with way more different requests.

for 5) how does the client know when the sync period is coming up for a change? Perhaps a slots_until_next_sync_committee_period or similar should be added to the snapshot information?

This can be easily computed knowing the config, genesis_time and genesis_validators_root of the network

@dapplion
Copy link
Collaborator Author

dapplion commented Dec 5, 2021

RE: @arnetheduck

This is great as a draft, but believe it's good to settle on a p2p protocol before enshrining / merging it such that implementations don't have to maintain two views of the same data that are slightly different - this work has started in ethereum/consensus-specs#2267 and should be completed first - we are in the process of implementing it and will be providing updates soon.

Thanks! Tho I believe there's value in iterating both publicly at the same time. Lodestar will tackle p2p next so happy to give feedback on ethereum/consensus-specs#2267 then

@holgerd77
Copy link

Will cc myself and @ryanio in here.

@etan-status
Copy link
Contributor

etan-status commented Apr 21, 2022

Feedback from discussions at Devconnect AMS:

See libp2p PR discussion: ethereum/consensus-specs#2802 (comment)

  • Align data types with libp2p once there is agreement there. The light client should receive the same objects regardless of the underlying transport.
    • Exception being that SSE does not necessarily require the selection proof that is being discussed (similar to other events types)
  • Add route for fetching latest light client update to enable use case of retrieving latest finalized block root
    • light_client/updates/latest
  • Align naming with best practices and make it consistent across transports
    • Data types: Same as libp2p
      • LightClientHeaderUpdate -> LightClientOptimisticUpdate
      • LightClientUpdate stays the same
      • LightClientSnapshotWithProof -> LightClientBootstrap
    • HTTP GET:
      • /lightclient/committee_updates?from={from}&to={to} -> light_client/updates?from={from}&to={to} (or use start_period / count to match libp2p?)
      • lightclient/head_update/ -> light_client/optimistic_update
      • lightclient/snapshot/{block_root} -> light_client/bootstrap/{block_root}
    • HTTP Server-Sent Event:
      • lightclient_head_update -> light_client_optimistic_update

@etan-status
Copy link
Contributor

etan-status commented May 10, 2022

Would also change from /eth2/v1/light_client to /eth2/v1/beacon/light_client/...as this data is about the beacon chain. It is also how the libp2p reqs are currently prefixed in proposal (at the very least, it should be consistent). On libp2p there is also the relation to the Status message which is another indicator that LC stuff should be under beacon umbrella.

etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/light_client/bootstrap/{block_root}`
- `/eth/v0/light_client/updates?from={from}&to={to}`
- `/eth/v0/light_client/finality_update`
- `/eth/v0/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/light_client/bootstrap/{block_root}`
- `/eth/v0/light_client/updates?from={from}&to={to}`
- `/eth/v0/light_client/finality_update`
- `/eth/v0/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/light_client/bootstrap/{block_root}`
- `/eth/v0/light_client/updates?from={from}&to={to}`
- `/eth/v0/light_client/finality_update`
- `/eth/v0/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/light_client/bootstrap/{block_root}`
- `/eth/v0/light_client/updates?from={from}&to={to}`
- `/eth/v0/light_client/finality_update`
- `/eth/v0/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/light_client/bootstrap/{block_root}`
- `/eth/v0/light_client/updates?start_period={start}&count={count}`
- `/eth/v0/light_client/finality_update`
- `/eth/v0/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/beacon/light_client/bootstrap/{block_root}`
- `/eth/v0/beacon/light_client/updates?start_period={start_period}&count={count}`
- `/eth/v0/beacon/light_client/finality_update`
- `/eth/v0/beacon/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
etan-status added a commit to status-im/nimbus-eth2 that referenced this pull request Jun 18, 2022
Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/beacon/light_client/bootstrap/{block_root}`
- `/eth/v0/beacon/light_client/updates?start_period={start_period}&count={count}`
- `/eth/v0/beacon/light_client/finality_update`
- `/eth/v0/beacon/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.
@etan-status
Copy link
Contributor

Adopted with a v0 suffix in Nimbus (without proofs endpoint)

Requests:

  • /eth/v0/beacon/light_client/bootstrap/{block_root}
  • /eth/v0/beacon/light_client/updates?start_period={start_period}&count={count}
  • /eth/v0/beacon/light_client/finality_update
  • /eth/v0/beacon/light_client/optimistic_update

HTTP Server-Sent Events (SSE):

  • light_client_finality_update_v0
  • light_client_optimistic_update_v0

status-im/nimbus-eth2#3775

zah pushed a commit to status-im/nimbus-eth2 that referenced this pull request Jun 19, 2022
* adopt LC REST API with v0 suffix (without proofs)

Adopts the light client data REST API used by Lodestar as defined in
ethereum/beacon-APIs#181 with a v0 suffix.

Requests:
- `/eth/v0/beacon/light_client/bootstrap/{block_root}`
- `/eth/v0/beacon/light_client/updates?start_period={start_period}&count={count}`
- `/eth/v0/beacon/light_client/finality_update`
- `/eth/v0/beacon/light_client/optimistic_update`

HTTP Server-Sent Events (SSE):
- `light_client_finality_update_v0`
- `light_client_optimistic_update_v0`

More work is needed to adopt the proofs endpoint, it is not included.

* initialize event queues

* register event topics
@zah
Copy link

zah commented Jul 2, 2022

It would be useful if all requests support returning SSZ data if the Accept: application/octet-stream header is provided. To make this possible, we need to specify an upper limit to the number of results of the getCommitteeUpdates request (in order to encode the result as List[LightClientUpdate, Limit] in SSZ).

@etan-status
Copy link
Contributor

etan-status commented Jul 2, 2022

The format is not that simple, as each element could be from different forks. The list does not solely contain altair.LightClientUpdate but may contain different updates in the future.

On Gossipsub, this is solved by prepending the fork digest to each item (similar encoding as a SSZ union, but not processed as a SSZ union as some legacy endpoints also support having an empty fork digest to indicate phase0).

Technically, you could also peek into the first 8 bytes of the SSZ response to determine attested_header.slot and infer the fork digest from there. A more general approach would be desirable though, as the 4 bytes do not add meaningful overhead.

Note that SSZ unions are not well-supported in all SSZ encoding libraries. (or only pseudo-supported with a type of 0).

@dapplion
Copy link
Collaborator Author

dapplion commented Jul 5, 2022

It would be useful if all requests support returning SSZ data if the Accept: application/octet-stream header is provided. To make this possible, we need to specify an upper limit to the number of results of the getCommitteeUpdates request (in order to encode the result as List[LightClientUpdate, Limit] in SSZ).

@etan-status something like this would be valuable for the beacon -> validator API too. Some previous discussion on how to handle fork versioning

@dapplion dapplion dismissed a stale review via 818e21b September 15, 2022 13:15
@dapplion
Copy link
Collaborator Author

After discussing with @etan-status its best to separate the proof route into a different namespace TBD

etan-status added a commit to etan-status/beacon-APIs that referenced this pull request Sep 22, 2022
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 ethereum#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.
etan-status added a commit to etan-status/beacon-APIs that referenced this pull request Sep 22, 2022
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 ethereum#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.
etan-status added a commit to etan-status/beacon-APIs that referenced this pull request Sep 22, 2022
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 ethereum#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.
@dapplion
Copy link
Collaborator Author

dapplion commented Oct 4, 2022

Proofs endpoint should be tackled separately

@dapplion dapplion closed this Oct 4, 2022
Ingridmichelledev added a commit to Ingridmichelledev/API-beacons that referenced this pull request Mar 3, 2023
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 ethereum/beacon-APIs#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants