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
- The `validate_merge_block` function MUST NOT raise an assertion if both the
`pow_block` and `pow_parent` are unknown to the execution engine.
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
sets:
2021-12-05 23:07:54 +00:00
- `valid_roots: Set[Root]` : `hash_tree_root(block)` where
2021-12-13 06:09:09 +00:00
`block.body.execution_payload` is known to be `VALID` .
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-13 06:09:09 +00:00
Notably, `optimistic_roots` only includes blocks which have execution enabled.
On the other hand, `valid_roots` contains blocks *with or without* execution
enabled (i.e., all blocks).
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` .
### Execution Engine Errors
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.
## 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-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:
hash_tree_root(block) in optimistic_roots
```
```python
def latest_valid_ancestor(block: BeaconBlock) -> Optional[BeaconBlock]:
while block.parent_root != Root():
if not is_optimistic(block):
return block
block = get_block(block.parent_root)
return None
```
2021-12-13 06:09:09 +00:00
```python
def recent_valid_ancestor(block: BeaconBlock) -> Optional[BeaconBlock]:
ancestor = latest_valid_ancestor(block)
if ancestor is None or ancestor.slot + SLOTS_PER_EPOCH >= block.slot:
return None
return ancestor
```
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-05 23:07:54 +00:00
### Block production
A optimistic validator MUST NOT produce a block (i.e., sign across the
`DOMAIN_BEACON_PROPOSER` domain), unless one of the follow exceptions are met:
#### Exception 1.
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)` .
2021-12-13 06:09:09 +00:00
If the latest valid ancestor is `None` , the validator MUST NOT produce a block.
2021-12-05 23:07:54 +00:00
### Attesting
An optimistic validator MUST NOT participate in attestation (i.e., sign across the
`DOMAIN_BEACON_ATTESTER` , `DOMAIN_SELECTION_PROOF` or
`DOMAIN_AGGREGATE_AND_PROOF` domains), unless one of the follow exceptions are
met:
#### Exception 1.
2021-12-13 06:09:09 +00:00
If the justified block is fully verified (i.e., `not
is_optimistic(justified_block)`, the validator MAY sign across the following
domains:
- `DOMAIN_BEACON_ATTESTER` : where `attestation.data.beacon_block_root == hash_tree_root(recent_valid_ancestor(head))` .
- `DOMAIN_AGGREGATE_AND_PROOF` and `DOMAIN_SELECTION_PROOF` : where `aggregate.message.aggregate.data.beacon_block_root == hash_tree_root(recent_valid_ancestor(head))`
If the recent valid ancestor is `None` , the validator MUST NOT participate in
attestation.
### 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
### Topics and Messages on Gossipsub
#### `beacon_block`
An optimistic validator MUST subscribe to the `beacon_block` topic. Propagation
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` .
#### `beacon_aggregate_and_proof`
An optimistic validator MUST NOT subscribe to the `beacon_aggregate_and_proof`
topic.
#### `voluntary_exit`
An optimistic validator MUST NOT subscribe to the `voluntary_exit` topic.
#### `proposer_slashing`
An optimistic validator MUST NOT subscribe to the `proposer_slashing` topic.
#### `attester_slashing`
An optimistic validator MUST NOT subscribe to the `attester_slashing` topic.