eth2.0-specs/sync/optimistic.md

227 lines
8.3 KiB
Markdown
Raw Normal View History

2021-12-05 23:07:54 +00:00
# Optimistic Sync
## Introduction
2021-12-13 06:09:09 +00:00
In order to provide a syncing execution engine with a partial view of the head
of the chain, it may be desirable for a consensus engine to import beacon
blocks without verifying the execution payloads. This partial sync is called an
*optimistic sync*.
2021-12-05 23:07:54 +00:00
## Mechanisms
To perform an optimistic sync:
- The `execute_payload` function MUST return `True` if the execution
2021-12-13 06:09:09 +00:00
engine returns `SYNCING` or `VALID`. An `INVALID` response MUST return `False`.
2021-12-05 23:07:54 +00:00
In addition to these changes to validation, the consensus engine MUST be able
2021-12-13 06:09:09 +00:00
to ascertain, after import, which blocks returned `SYNCING` and which returned
`VALID`. This document will assume that consensus engines store the following
2021-12-14 04:51:02 +00:00
set:
2021-12-05 23:07:54 +00:00
- `optimistic_roots: Set[Root]`: `hash_tree_root(block)` where
2021-12-13 06:09:09 +00:00
`block.body.execution_payload` is known to be `SYNCING`.
2021-12-05 23:07:54 +00:00
2021-12-14 05:21:30 +00:00
Notably, blocks included in `optimistic_roots` have passed all verifications
included in `process_block` (noting the modifications to the
`execute_payload`). I.e., the blocks are fully verified but awaiting execution
of the `ExecutionPayload`.
2021-12-05 23:07:54 +00:00
A consensus engine MUST be able to retrospectively (i.e., after import) modify
2021-12-13 06:09:09 +00:00
the status of `SYNCING` blocks to be either `VALID` or `INVALID` based upon responses
2021-12-05 23:07:54 +00:00
from an execution engine. I.e., perform the following transitions:
2021-12-13 06:09:09 +00:00
- `SYNCING` -> `VALID`
- `SYNCING` -> `INVALID`
2021-12-05 23:07:54 +00:00
2021-12-13 06:09:09 +00:00
When a block transitions from `SYNCING` -> `VALID`, all *ancestors* of the block MUST
also transition from `SYNCING` -> `VALID`.
2021-12-05 23:07:54 +00:00
2021-12-13 06:09:09 +00:00
When a block transitions from `SYNCING` -> `INVALID`, all *descendants* of the
block MUST also transition from `SYNCING` -> `INVALID`.
2021-12-14 05:22:52 +00:00
When a node transitions from the `SYNCING` state it is removed from the set of
`optimistic_roots`.
2021-12-13 06:09:09 +00:00
### Execution Engine Errors
2021-12-13 06:09:09 +00:00
A consensus engine MUST NOT interpret an error or failure to respond to a
message as a `SYNCING`, `VALID` or `INVALID` response. A consensus engine MAY
queue such a message for later processing.
2021-12-14 04:44:15 +00:00
### Assumptions about Execution Engine Behaviour
This specification assumes execution engines will only return `SYNCING` when
there is insufficient information available to make a `VALID` or `INVALID`
determination on the given `ExecutionPayload` (e.g., the parent payload is
unknown). Specifically, `SYNCING` responses should be fork-specific; the search
for a block on one chain MUST NOT trigger a `SYNCING` response for another
chain.
2021-12-14 05:42:35 +00:00
### Re-Orgs
The consensus engine MUST support any chain reorganisation which does *not*
affect the justified checkpoint. The consensus engine MAY support re-orgs
beyond the justified checkpoint.
If the justified checkpoint transitions from `SYNCING` -> `INVALID`, a
consensus engine MAY choose to alert the user and force the application to
exit.
2021-12-13 06:09:09 +00:00
## Merge Transition
To protect against attacks during the transition from empty `ExecutionPayload`
values to those which include the terminal PoW block, a consensus engine MUST
NOT perform an optimistic sync unless the `finalized_checkpoint.root` of the head
block references a block for which
`is_execution_enabled(head_state, head_block.body) == True`.
TODO: this restriction is very onerous, however it is the best known remedy for
the attack described in https://hackmd.io/S5ZEVhsNTqqfJirTAkBPlg I hope we can
do better.
2021-12-05 23:07:54 +00:00
## Fork Choice
2021-12-13 06:09:09 +00:00
Consensus engines MUST support removing from fork choice blocks that transition
from `SYNCING` to `INVALID`. Specifically, a block deemed `INVALID` at any
point MUST NOT be included in the canonical chain and the weights from those
`INVALID` blocks MUST NOT be applied to any `VALID` or `SYNCING` ancestors.
2021-12-05 23:07:54 +00:00
2021-12-14 05:10:19 +00:00
## Checkpoint Sync (Weak Subjectivity Sync)
A consensus engine MAY assume that the `ExecutionPayload` of a block used for
checkpoint sync is `VALID`.
2021-12-13 06:09:09 +00:00
### Helpers
2021-12-05 23:07:54 +00:00
Let `head_block: BeaconBlock` be the result of calling of the fork choice
algorithm at the time of block production. Let `justified_block: BeaconBlock`
be the latest current justified ancestor ancestor of the `head_block`.
```python
def is_optimistic(block: BeaconBlock) -> bool:
2021-12-13 08:15:53 +00:00
hash_tree_root(block) in optimistic_roots
2021-12-05 23:07:54 +00:00
```
```python
2021-12-13 08:15:53 +00:00
def latest_valid_ancestor(block: BeaconBlock) -> BeaconBlock:
2021-12-14 04:54:33 +00:00
while True:
2021-12-14 04:53:03 +00:00
if not is_optimistic(block) or block.parent_root == Root():
return block
2021-12-13 08:15:53 +00:00
block = get_block(block.parent_root)
2021-12-13 06:09:09 +00:00
```
Let only a node which returns `is_optimistic(head) == True` be an *optimistic
node*. Let only a validator on an optimistic node be an *optimistic validator*.
2021-12-05 23:07:54 +00:00
2021-12-13 08:02:45 +00:00
When this specification only defines behaviour for an optimistic
node/validator, but *not* for the non-optimistic case, assume default
behaviours without regard for optimistic sync.
## Validator assignments
An entirely optimistically synced node is *not* a full node. It is unable to
produce blocks, since an execution engine cannot produce a payload upon an
unknown parent. It cannot faithfully attest to the head block of the chain,
since it has not fully verified that block.
2021-12-13 08:15:53 +00:00
### Block Production
2021-12-05 23:07:54 +00:00
A optimistic validator MUST NOT produce a block (i.e., sign across the
2021-12-13 08:15:53 +00:00
`DOMAIN_BEACON_PROPOSER` domain), unless one of the following exceptions are
met:
2021-12-05 23:07:54 +00:00
2021-12-13 08:15:53 +00:00
#### Block Production Exception 1.
2021-12-05 23:07:54 +00:00
If the justified block is fully verified (i.e., `not
2021-12-13 06:09:09 +00:00
is_optimistic(justified_block)`, the validator MAY produce a block upon
2021-12-05 23:07:54 +00:00
`latest_valid_ancestor(head)`.
### Attesting
An optimistic validator MUST NOT participate in attestation (i.e., sign across the
`DOMAIN_BEACON_ATTESTER`, `DOMAIN_SELECTION_PROOF` or
2021-12-13 08:03:35 +00:00
`DOMAIN_AGGREGATE_AND_PROOF` domains).
2021-12-13 06:09:09 +00:00
### Participating in Sync Committees
An optimistic validator MUST NOT participate in sync committees (i.e., sign across the
`DOMAIN_SYNC_COMMITTEE`, `DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF` or
`DOMAIN_CONTRIBUTION_AND_PROOF` domains).
2021-12-13 08:02:45 +00:00
## P2P Networking
2021-12-13 08:15:53 +00:00
### The Gossip Domain (gossipsub)
2021-12-13 08:02:45 +00:00
#### `beacon_block`
2021-12-13 08:15:53 +00:00
An optimistic validator MAY subscribe to the `beacon_block` topic. Propagation
2021-12-13 08:02:45 +00:00
validation conditions are modified as such:
Do not apply the existing condition:
- [REJECT] The block's parent (defined by block.parent_root) passes validation.
Instead, apply the new condition:
- [REJECT] The block's parent (defined by block.parent_root) passes validation,
*and* `block.parent root not in optimistic_roots`.
2021-12-14 04:51:26 +00:00
#### Other Topics
2021-12-13 08:02:45 +00:00
2021-12-14 04:51:26 +00:00
An optimistic node MUST NOT subscribe to the following topics:
2021-12-13 08:02:45 +00:00
2021-12-14 04:51:26 +00:00
- `beacon_aggregate_and_proof`
- `voluntary_exit`
- `proposer_slashing`
- `attester_slashing`
- `beacon_attestation_{subnet_id}`
- `sync_committee_contribution_and_proof`
- `sync_committee_{subnet_id}`
2021-12-13 08:02:45 +00:00
2021-12-14 04:51:26 +00:00
Once the node ceases to be optimistic, it MAY re-subscribe to the aformentioned
topics.
2021-12-13 08:25:33 +00:00
### The Req/Resp Domain
#### BeaconBlocksByRange (v1, v2)
Consensus engines MUST NOT include any block in a response where
`is_optimistic(block) == False`.
#### BeaconBlocksByRoot (v1, v2)
Consensus engines MUST NOT include any block in a response where
2021-12-14 03:53:04 +00:00
`is_optimistic(block) == True`.
2021-12-13 08:25:33 +00:00
#### Status
An optimistic node MUST use the `latest_valid_ancestor(head)` block to form
responses, rather than the head block. Specifically, an optimistic node must
form a `Status` message as so:
The fields are, as seen by the client at the time of sending the message:
- `fork_digest`: As previously defined.
- `finalized_root`: `state.finalized_checkpoint.root` for the state corresponding to the latest valid ancestor block
(Note this defaults to `Root(b'\x00' * 32)` for the genesis finalized checkpoint).
- `finalized_epoch`: `state.finalized_checkpoint.epoch` for the state corresponding to the latest valid ancestor block.
- `head_root`: The `hash_tree_root` root of the current latest valid ancestor block (`BeaconBlock`).
- `head_slot`: The slot of the block corresponding to `latest_valid_ancestor(head)`.
2021-12-14 05:11:40 +00:00
## Ethereum Beacon APIs
Consensus engines which provide an implementation of the [Ethereum Beacon
APIs](https://github.com/ethereum/beacon-APIs) must take care to avoid
presenting optimistic blocks as fully-verified blocks.
When information about an optimistic block is requested, the consensus engine:
- MUST NOT return a "success"-type response (e.g., 2xx).
- MAY return an "empty"-type response (e.g., 404).
- MAY return a "beacon node is currently syncing"-type response (e.g., 503).
When `is_optimistic(head) == True`, the consensus engine:
- MAY substitute the head block with `latest_valid_ancestor(block)`.
- MAY return a "beacon node is currently syncing"-type response (e.g., 503).