-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[WIP] Light client protocol + Req/Resp interaction #2267
Conversation
185f20d
to
729ccf2
Compare
@@ -23,3 +24,23 @@ def uint_to_bytes(n: uint) -> bytes: | |||
# Helper method for typing copies, and avoiding a example_input.copy() method call, instead of copy(example_input) | |||
def copy(obj: V) -> V: | |||
return obj.copy() | |||
|
|||
|
|||
def build_proof(anchor, leaf_index): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: it's for the incoming get_light_client_update
helper
) | ||
``` | ||
|
||
No Response Content. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is a push-update, and there is no explicit subscription kind of approach for a light-client, then we should spec out when and how often the server pushes the update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which begs the question -- can we have this by default on gossip?
Even so, I would suspect we need req/resp as backup, but as for the req/resp backup, I would suspect this might need to be pull and have some sort of payload for the request. If my lightclient has been offline for a day, I need to be able to make specific requests to catchup to the head and can't rely entirely on head updates because I'm not yet there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relying on LightClientUpdate data structure to update a lightclient head is very wasteful since it only need to get the next_sync_committee pubkeys once every 256 epochs. To be honest the LightClientUpdate data structure works fine in a spec but it's not great in practice. The process of syncing can be split into two steps:
- Get the pubkeys of the current sync committee. Use req/resp on demand to query LightClientUpdate(s)
- Get latest SyncAggregate + header. More optimal to be gossiped once or more per slot.
However, gossiping SyncAggregate has an issue of how to decide which messages to accept and ignore. There are many combinations of the same signatures that results in different SyncAggregate objects (i.e. #2183).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A general comments and questions to start
|
||
#### GetLightClientSnapshot | ||
|
||
**Protocol ID:** `/eth2/beacon_chain/req/get_light_client_snapshot/1/` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not certain that this needs to be on the req/resp protocol. Essentially, LightClientSnapshot
is something kept locally. A light client starts with some snapshot and then uses iterative LightClientUpdate
s to transition their local snapshot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, Req/Resp was the simplest way to get a snapshot for MVP.
Alternatively, what do you think about saying that we expect 3rd party to provide LightClientSnapshot
+ Merkle proofs or multi-proof of each field, where the proof can be verified against WS source?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, what do you think about saying that we expect 3rd party to provide LightClientSnapshot + Merkle proofs or multi-proof of each field, where the proof can be verified against WS source?
Agree 👍
) | ||
``` | ||
|
||
No Response Content. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which begs the question -- can we have this by default on gossip?
Even so, I would suspect we need req/resp as backup, but as for the req/resp backup, I would suspect this might need to be pull and have some sort of payload for the request. If my lightclient has been offline for a day, I need to be able to make specific requests to catchup to the head and can't rely entirely on head updates because I'm not yet there
|
||
## Sync protocol | ||
|
||
Note that in this syncing mechanism, the server is trusted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you say the server is trusted?
The proofs make this trustless from a safety standpoint (assuming no sync committee corruption)
### Initialization | ||
|
||
1. The client sends [`Status` message](./../../phase0/p2p-interface.md#status) to the server to exchange the status information. | ||
2. Instead of sending [`BeaconBlocksByRange` request](./../../phase0/p2p-interface.md#beaconblocksbyrange) in the beacon chain syncing, the client sends [`GetLightClientSnapshot` request](./p2p-interface.md#getlightclientsnapshot) to the server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So a light client must not just trust the server for a good snapshot. They must instead start from a known safe place and transition trustlessly from there
Co-authored-by: Danny Ryan <[email protected]>
@@ -77,8 +113,7 @@ class LightClientUpdate(Container): | |||
finality_header: BeaconBlockHeader | |||
finality_branch: Vector[Bytes32, floorlog2(FINALIZED_ROOT_INDEX)] | |||
# Sync committee aggregate signature | |||
sync_committee_bits: Bitvector[SYNC_COMMITTEE_SIZE] | |||
sync_committee_signature: BLSSignature | |||
sync_aggregate: SyncAggregate | |||
# Fork version for the aggregate signature | |||
fork_version: Version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe almost all consumers of this data structure can compute the fork_version on their own. The only scenario where it could make sense is in LC embedded in blockchains, but even then you can input fork info in other ways.
) | ||
``` | ||
|
||
The `LightClientSnapshot` SSZ container defined in [light client sync protocol](./sync-protocol.md#lightclientsnapshot). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To initialize a lightclient you don't need the next_sync_committee, but only the current_sync_committee. You can get the next via syncing.
WIP!!!
New and moved files