-
Notifications
You must be signed in to change notification settings - Fork 32
pqdevnet0: client specs #8
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
Changes from all commits
2f6a6e8
1dca1e0
b2bb6be
4872e53
f7b237b
eb8e1d5
7203fb5
36db569
e6b93ff
6f81d11
20f5237
c5d936d
9883d92
acccf3e
63717aa
d4881e1
a599d14
c67e397
e38593e
4c3099c
ebaf501
d84d5da
1b469e8
a236de3
ad9bc63
dd98282
ab3943a
29913a2
65daac2
52e8e9f
e600336
6ef1f10
cdcf9ae
d19d93d
0788d88
14d5ac2
72909be
64acd24
c551aa2
884cc1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,5 +9,7 @@ keccak | |
| blake | ||
| merkle | ||
| trie | ||
| ream | ||
| rlp | ||
| ssz | ||
| zeam | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Lean Consensus Experimental Chain | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Time parameters | ||
|
|
||
| | Name | Value | Unit | Duration | | ||
| | ------------------------------------- | ------------------------- | :----------: | :-----------: | | ||
| | `SLOT_DURATION_MS` | `uint64(4000)` | milliseconds | 4 seconds | | ||
| | `INTERVALS_PER_SLOT` | `uint64(4)` | intervals | 1 second | | ||
|
|
||
| ## Presets | ||
|
|
||
| ### State list lengths | ||
|
|
||
| | Name | Value | Unit | Duration | | ||
| | ------------------------------ | ------------------------------------- | :--------------: | :-----------: | | ||
| | `HISTORICAL_ROOTS_LIMIT` | `uint64(2**18)` (= 262,144) | historical roots | 12.1 days | | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| | `VALIDATOR_REGISTRY_LIMIT` | `uint64(2**12)` (= 4,096) | validators | | | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # Containers | ||
|
|
||
| ## `Config` | ||
|
|
||
| ```python | ||
| class Config(Container): | ||
| // temporary property to support simplified round robin block production in absence of randao & deposit mechanisms | ||
| num_validators: uint64 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| genesis_time: uint64 | ||
| ``` | ||
|
|
||
| ## `Checkpoint` | ||
|
|
||
| ```python | ||
| class Checkpoint(Container): | ||
| root: Bytes32 | ||
| slot: uint64 | ||
| ``` | ||
|
|
||
| ## `State` | ||
|
|
||
| ```python | ||
| class State(Container): | ||
| config: Config | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| slot: uint64 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| latest_block_header: BlockHeader | ||
|
|
||
| latest_justified: Checkpoint | ||
| latest_finalized: Checkpoint | ||
|
|
||
| historical_block_hashes: List[Bytes32, HISTORICAL_ROOTS_LIMIT] | ||
| justified_slots: List[bool, HISTORICAL_ROOTS_LIMIT] | ||
|
|
||
| # Diverged from 3SF-mini.py: | ||
| # Flattened `justifications: Dict[str, List[bool]]` for SSZ compatibility | ||
| justifications_roots: List[Bytes32, HISTORICAL_ROOTS_LIMIT] | ||
| justifications_validators: Bitlist[ | ||
| HISTORICAL_ROOTS_LIMIT * VALIDATOR_REGISTRY_LIMIT | ||
| ] | ||
| ``` | ||
|
|
||
| ## `Block` | ||
|
|
||
| ```python | ||
| class Block(Container): | ||
| slot: uint64 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| proposer_index: uin64 | ||
| parent_root: Bytes32 | ||
| state_root: Bytes32 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| body: BlockBody | ||
| ``` | ||
|
|
||
| ## `BlockBody` | ||
|
|
||
|
|
||
| ```python | ||
| class BlockBody(Container): | ||
| votes: List[Vote, VALIDATOR_REGISTRY_LIMIT] | ||
| ``` | ||
|
|
||
| Remark: `votes` will be replaced by aggregated attestations. | ||
|
|
||
| ## `SignedBlock` | ||
|
|
||
| ```python | ||
| class SignedBlock(Container): | ||
| message: Block, | ||
| signature: Bytes32, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To update to exact size (~3KiB) based on researchers' input |
||
| ``` | ||
|
|
||
| ## `Vote` | ||
|
|
||
| ```python | ||
| class Vote(Container): | ||
| validator_id: uint64 | ||
| slot: uint64 | ||
| head: Checkpoint | ||
| target: Checkpoint | ||
| source: Checkpoint | ||
| ``` | ||
|
|
||
| ## `SignedVote` | ||
|
|
||
| ```python | ||
| class SignedVote(Container): | ||
| data: Vote, | ||
| signature: Bytes32, | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To update to exact size (~3KiB) based on researchers' input |
||
| ``` | ||
|
|
||
| ## Remarks | ||
|
|
||
| - The signature type is still to be determined so `Bytes32` is used in the | ||
| interim. The actual signature size is expected to be a lot larger (~3 KiB). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| # Networking | ||
|
|
||
| ## Setup | ||
|
|
||
| - Transport: QUIC on IPv4, secured by TLS 1.3 with `secp256k1` identities | ||
| - Protocol negotiation: [multistream-select 1.0](https://github.com/multiformats/multistream-select/) | ||
| - Multiplexing: Native support by QUIC | ||
| - Gossip: [gossipsub v1](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md) | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ## Node identification | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Nodes are defined as a list of their ENRs in a yaml file at [`src/lean_spec/client/nodes.yaml`](../../src/lean_spec/client/nodes.yaml). | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| For example: | ||
|
|
||
| ```yaml | ||
| - enr:-Ku4QHqVeJ8PPICcWk1vSn_XcSkjOkNiTg6Fmii5j6vUQgvzMc9L1goFnLKgXqBJspJjIsB91LTOleFmyWWrFVATGngBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAMRHkWJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyg | ||
| - enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg | ||
| - enr:-Ku4QG-2_Md3sZIAUebGYT6g0SMskIml77l6yR-M_JXc-UdNHCmHQeOiMLbylPejyJsdAPsTHJyjJB2sYGDLe0dn8uYBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhBLY-NyJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyg | ||
| ``` | ||
|
|
||
| ## ENR structure (modified) | ||
|
|
||
| The Ethereum Node Record (ENR) for an Ethereum consensus client MUST contain the | ||
| following entries (exclusive of the sequence number and signature, which MUST be | ||
| present in an ENR): | ||
|
|
||
| - The compressed secp256k1 publickey, 33 bytes (`secp256k1` field). | ||
|
|
||
| The ENR MAY contain the following entries: | ||
|
|
||
| - An IPv4 address (`ip` field). | ||
| - An IPv4 QUIC port (`quic` field) representing the local libp2p QUIC (UDP) | ||
| listening port. | ||
|
|
||
| Specifications of these parameters can be found in the | ||
| [ENR Specification](http://eips.ethereum.org/EIPS/eip-778). | ||
|
|
||
| ## Configuration | ||
|
|
||
| This section outlines configurations that are used in this spec. | ||
|
|
||
| | Name | Value | Description | | ||
| | ------------------------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------- | | ||
| | `MAX_REQUEST_BLOCKS` | `2**10` (= 1024) | Maximum number of blocks in a single request | | ||
| | `MESSAGE_DOMAIN_INVALID_SNAPPY` | `DomainType('0x00000000')` | 4-byte domain for gossip message-id isolation of *invalid* snappy messages | | ||
| | `MESSAGE_DOMAIN_VALID_SNAPPY` | `DomainType('0x01000000')` | 4-byte domain for gossip message-id isolation of *valid* snappy messages | | ||
|
|
||
| ## Gossip domain | ||
|
|
||
| **Protocol ID:** `/meshsub/1.0.0` | ||
|
|
||
| **Gossipsub Parameters** | ||
|
|
||
| The following gossipsub | ||
| [parameters](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md#parameters) | ||
| will be used: | ||
|
|
||
| - `D` (topic stable mesh target count): 8 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - `D_low` (topic stable mesh low watermark): 6 | ||
| - `D_high` (topic stable mesh high watermark): 12 | ||
| - `D_lazy` (gossip target): 6 | ||
| - `heartbeat_interval` (frequency of heartbeat, seconds): 0.7 | ||
| - `fanout_ttl` (ttl for fanout maps for topics we are not subscribed to but have | ||
| published to, seconds): 60 | ||
| - `mcache_len` (number of windows to retain full messages in cache for `IWANT` | ||
| responses): 6 | ||
| - `mcache_gossip` (number of windows to gossip about): 3 | ||
| - `seen_ttl` (expiry time for cache of seen message ids, seconds): | ||
| SECONDS_PER_SLOT * SLOTS_PER_EPOCH * 2 | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #### Topics and messages | ||
|
|
||
| Topics are plain UTF-8 strings and are encoded on the wire as determined by | ||
| protobuf (gossipsub messages are enveloped in protobuf messages). Topic strings | ||
| have form: `/leanconsensus/devnet{N}/Name/Encoding`. This defines both the type of | ||
| data being sent on the topic and how the data field of the message is encoded. | ||
|
|
||
| - `Name` - see table below | ||
| - `Encoding` - the encoding strategy describes a specific representation of | ||
| bytes that will be transmitted over the wire. See the [Encodings](#Encodings) | ||
| section for further details. | ||
|
|
||
| The optional `from` (1), `seqno` (3), `signature` (5) and `key` (6) protobuf | ||
| fields are omitted from the message, since messages are identified by content, | ||
| anonymous, and signed where necessary in the application layer. | ||
|
|
||
| The `message-id` of a gossipsub message MUST be the following 20 byte value | ||
| computed from the message data: | ||
|
|
||
| - If `message.data` has a valid snappy decompression, set `message-id` to the | ||
| first 20 bytes of the `SHA256` hash of the concatenation of | ||
| `MESSAGE_DOMAIN_VALID_SNAPPY` with the snappy decompressed message data, i.e. | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| `SHA256(MESSAGE_DOMAIN_VALID_SNAPPY + snappy_decompress(message.data))[:20]`. | ||
| - Otherwise, set `message-id` to the first 20 bytes of the `SHA256` hash of the | ||
| concatenation of `MESSAGE_DOMAIN_INVALID_SNAPPY` with the raw message data, | ||
| i.e. `SHA256(MESSAGE_DOMAIN_INVALID_SNAPPY + message.data)[:20]`. | ||
|
|
||
| Where relevant, clients MUST reject messages with `message-id` sizes other than | ||
| 20 bytes. | ||
|
|
||
| *Note*: The above logic handles two exceptional cases: (1) multiple snappy | ||
| `data` can decompress to the same value, and (2) some message `data` can fail to | ||
| snappy decompress altogether. | ||
|
|
||
| The payload is carried in the `data` field of a gossipsub message, and varies | ||
| depending on the topic: | ||
|
|
||
| | Name | Message Type | | ||
| | -------------------------------- | ------------------------- | | ||
| | `block` | `SignedBlock` | | ||
| | `vote` | `SignedVote` | | ||
|
|
||
| Clients MUST reject (fail validation) messages containing an incorrect type, or | ||
| invalid payload. | ||
|
|
||
| #### Encodings | ||
|
|
||
| Topics are post-fixed with an encoding. Encodings define how the payload of a | ||
| gossipsub message is encoded. | ||
|
|
||
| - `ssz_snappy` - All objects are SSZ-encoded and then compressed with | ||
| [Snappy](https://github.com/google/snappy) block compression. Example: The | ||
| lean block topic string is `/leanconsensus/devnet{N}/block/ssz_snappy`, | ||
| and the data field of a gossipsub message is an `Block` that has been | ||
| SSZ-encoded and then compressed with Snappy. | ||
|
|
||
| ### The Req/Resp domain | ||
|
|
||
| #### Encoding strategies | ||
|
|
||
| The token of the negotiated protocol ID specifies the type of encoding to be | ||
| used for the req/resp interaction. Only one value is possible at this time: | ||
|
|
||
| - `ssz_snappy`: The contents are first | ||
| [SSZ-encoded](../../ssz/simple-serialize.md) and then compressed with | ||
| [Snappy](https://github.com/google/snappy) frames compression. For objects | ||
| containing a single field, only the field is SSZ-encoded not a container with | ||
| a single field. For example, the `BlocksByRoot` request is an SSZ-encoded | ||
| list of `Root`'s. | ||
|
|
||
| #### Messages | ||
|
|
||
| ##### Status v1 | ||
|
|
||
| **Protocol ID:** `/leanconsensus/req/status/1/` | ||
|
|
||
| Request, Response Content: | ||
|
|
||
| ``` | ||
| ( | ||
| finalized_root: Bytes32 | ||
| finalized_slot: uint64 | ||
| head_root: Bytes32 | ||
| head_slot: uint64 | ||
| ) | ||
| ``` | ||
|
|
||
| The fields are, as seen by the client at the time of sending the message: | ||
|
|
||
| - `finalized_root`: `store.finalized_checkpoint.root` according to | ||
| [3SF-mini](https://github.com/ethereum/research/tree/master/3sf-mini). | ||
| (Note this defaults to `Root(b'\x00' * 32)` for the genesis finalized | ||
| checkpoint). | ||
| - `finalized_epoch`: `store.finalized_checkpoint.epoch` according to | ||
| [3SF-mini](https://github.com/ethereum/research/tree/master/3sf-mini). | ||
| - `head_root`: The `hash_tree_root` root of the current head block | ||
| (`Block`). | ||
| - `head_slot`: The slot of the block corresponding to the `head_root`. | ||
|
|
||
| The dialing client MUST send a `Status` request upon connection. | ||
|
|
||
| The request/response MUST be encoded as an SSZ-container. | ||
|
|
||
| The response MUST consist of a single `response_chunk`. | ||
|
|
||
| Clients SHOULD immediately disconnect from one another following the handshake | ||
| above under the following conditions: | ||
|
|
||
| 1. If the (`finalized_root`, `finalized_epoch`) shared by the peer is not in the | ||
| client's chain at the expected epoch. For example, if Peer 1 sends (root, | ||
| epoch) of (A, 5) and Peer 2 sends (B, 3) but Peer 1 has root C at epoch 3, | ||
| then Peer 1 would disconnect because it knows that their chains are | ||
| irreparably disjoint. | ||
|
|
||
| Once the handshake completes, the client with the lower `finalized_epoch` or | ||
| `head_slot` (if the clients have equal `finalized_epoch`s) SHOULD request blocks | ||
| from its counterparty via the `BlocksByRoot` request. | ||
|
|
||
| *Note*: Under abnormal network condition or after some rounds of | ||
| `BlocksByRoot` requests, the client might need to send `Status` request | ||
| again to learn if the peer has a higher head. Implementers are free to implement | ||
| such behavior in their own way. | ||
|
|
||
| ##### BlocksByRoot v1 | ||
|
|
||
| **Protocol ID:** `/leanconsensus/req/blocks_by_root/1/` | ||
|
|
||
| Request Content: | ||
|
|
||
| ``` | ||
| ( | ||
| List[Root, MAX_REQUEST_BLOCKS] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we define MAX_REQUEST_BLOCKS here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copied over This is |
||
| ) | ||
| ``` | ||
|
|
||
| Response Content: | ||
|
|
||
| ``` | ||
| ( | ||
| List[SignedBlock, MAX_REQUEST_BLOCKS] | ||
| ) | ||
| ``` | ||
|
|
||
| Requests blocks by block root (= `hash_tree_root(SignedBlock.message)`). | ||
| The response is a list of `SignedBlock` whose length is less than or equal | ||
| to the number of requested blocks. It may be less in the case that the | ||
| responding peer is missing blocks. | ||
|
|
||
| `BlocksByRoot` is primarily used to recover recent blocks (e.g. when | ||
| receiving a block or attestation whose parent is unknown). | ||
|
|
||
| The request MUST be encoded as an SSZ-field. | ||
|
|
||
| The response MUST consist of zero or more `response_chunk`. Each _successful_ | ||
| `response_chunk` MUST contain a single `SignedBlock` payload. | ||
|
|
||
| Clients MUST respond with at least one block, if they have it. Clients MAY limit | ||
| the number of blocks in the response. | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Validator | ||
|
|
||
| ## Validator identification | ||
|
|
||
| To ensure a good distribution of block proposer duties in a round-robin manner | ||
| and avoid clashing IDs, validator IDs are pre-assigned to each client | ||
| implementation in a yaml file at | ||
| [`src/lean_spec/client/validators.yaml`](../../src/lean_spec/client/validators.yaml). | ||
unnawut marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| For example: | ||
|
|
||
| ```yaml | ||
| ream: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] | ||
| zeam: [1, 4, 7, 10, 13, 16, 19, 22, 25, 28] | ||
| quadrivium: [2, 5, 8, 11, 14, 17, 20, 23, 26, 29] | ||
| ``` | ||
|
|
||
| ## Block proposer selection | ||
|
|
||
| The block proposer shall be determined by the modulo of the current slot number | ||
| by the total number of validators, such that block proposers are determined in | ||
| a round-robin manner by the validator IDs. | ||
|
|
||
| ```py | ||
| def is_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool: | ||
| return get_current_slot() % state.config.num_validators == validator_index | ||
| ``` | ||
|
|
||
| ## Remarks | ||
|
|
||
| - This spec is still missing the file format for the centralized, pre-generated | ||
| OTS keys (if any) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| - enr:-Ku4QHqVeJ8PPICcWk1vSn_XcSkjOkNiTg6Fmii5j6vUQgvzMc9L1goFnLKgXqBJspJjIsB91LTOleFmyWWrFVATGngBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAMRHkWJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyg | ||
| - enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg | ||
| - enr:-Ku4QG-2_Md3sZIAUebGYT6g0SMskIml77l6yR-M_JXc-UdNHCmHQeOiMLbylPejyJsdAPsTHJyjJB2sYGDLe0dn8uYBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhBLY-NyJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyg |

Uh oh!
There was an error while loading. Please reload this page.