Tidy, finish duties
This commit is contained in:
parent
c99e48c60c
commit
38fffd3e2f
|
@ -2,52 +2,71 @@
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
In order to provide a syncing execution engine with a (partially-verified) view
|
In order to provide a syncing execution engine with a partial view of the head
|
||||||
of the head of the chain, it may be desirable for a consensus engine to import
|
of the chain, it may be desirable for a consensus engine to import beacon
|
||||||
beacon blocks without verifying the execution payloads. This partial sync is
|
blocks without verifying the execution payloads. This partial sync is called an
|
||||||
called an *optimistic sync*.
|
*optimistic sync*.
|
||||||
|
|
||||||
## Mechanisms
|
## Mechanisms
|
||||||
|
|
||||||
To perform an optimistic sync:
|
To perform an optimistic sync:
|
||||||
|
|
||||||
- The `execute_payload` function MUST return `True` if the execution
|
- The `execute_payload` function MUST return `True` if the execution
|
||||||
engine returns SYNCING or VALID. An INVALID response MUST return `False`.
|
engine returns `SYNCING` or `VALID`. An `INVALID` response MUST return `False`.
|
||||||
- The `validate_merge_block` function MUST NOT raise an assertion if both the
|
- The `validate_merge_block` function MUST NOT raise an assertion if both the
|
||||||
`pow_block` and `pow_parent` are unknown to the execution engine.
|
`pow_block` and `pow_parent` are unknown to the execution engine.
|
||||||
|
|
||||||
In addition to these changes to validation, the consensus engine MUST be able
|
In addition to these changes to validation, the consensus engine MUST be able
|
||||||
to ascertain, after import, which blocks returned SYNCING and which returned
|
to ascertain, after import, which blocks returned `SYNCING` and which returned
|
||||||
VALID. This document will assume consensus engines store the following sets:
|
`VALID`. This document will assume that consensus engines store the following
|
||||||
|
sets:
|
||||||
|
|
||||||
- `valid_roots: Set[Root]`: `hash_tree_root(block)` where
|
- `valid_roots: Set[Root]`: `hash_tree_root(block)` where
|
||||||
`block.body.execution_payload` is known to be VALID.
|
`block.body.execution_payload` is known to be `VALID`.
|
||||||
- `optimistic_roots: Set[Root]`: `hash_tree_root(block)` where
|
- `optimistic_roots: Set[Root]`: `hash_tree_root(block)` where
|
||||||
`block.body.execution_payload` is known to be SYNCING.
|
`block.body.execution_payload` is known to be `SYNCING`.
|
||||||
|
|
||||||
Notably, `optimistic_roots` only includes blocks which have execution enabled
|
Notably, `optimistic_roots` only includes blocks which have execution enabled.
|
||||||
whilst `valid_roots` contains blocks *with or without* execution enabled (i.e.,
|
On the other hand, `valid_roots` contains blocks *with or without* execution
|
||||||
all blocks).
|
enabled (i.e., all blocks).
|
||||||
|
|
||||||
A consensus engine MUST be able to retrospectively (i.e., after import) modify
|
A consensus engine MUST be able to retrospectively (i.e., after import) modify
|
||||||
the status of SYNCING blocks to be either VALID or INVALID based upon responses
|
the status of `SYNCING` blocks to be either `VALID` or `INVALID` based upon responses
|
||||||
from an execution engine. I.e., perform the following transitions:
|
from an execution engine. I.e., perform the following transitions:
|
||||||
|
|
||||||
- SYNCING -> VALID
|
- `SYNCING` -> `VALID`
|
||||||
- SYNCING -> INVALID
|
- `SYNCING` -> `INVALID`
|
||||||
|
|
||||||
When a block transitions from SYNCING -> VALID, all *ancestors* of the block MUST
|
When a block transitions from `SYNCING` -> `VALID`, all *ancestors* of the block MUST
|
||||||
also transition from SYNCING -> VALID.
|
also transition from `SYNCING` -> `VALID`.
|
||||||
|
|
||||||
When a block transitions from SYNCING -> INVALID, all *descendants* of the
|
When a block transitions from `SYNCING` -> `INVALID`, all *descendants* of the
|
||||||
block MUST also transition from SYNCING -> INVALID.
|
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.
|
||||||
|
|
||||||
## Fork Choice
|
## Fork Choice
|
||||||
|
|
||||||
Consensus engines MUST support removing blocks that transition from SYNCING to
|
Consensus engines MUST support removing from fork choice blocks that transition
|
||||||
INVALID. Specifically, an INVALID block MUST NOT be included in the canonical
|
from `SYNCING` to `INVALID`. Specifically, a block deemed `INVALID` at any
|
||||||
chain and the weights from INVALID blocks MUST NOT be applied to any VALID or
|
point MUST NOT be included in the canonical chain and the weights from those
|
||||||
SYNCING ancestors.
|
`INVALID` blocks MUST NOT be applied to any `VALID` or `SYNCING` ancestors.
|
||||||
|
|
||||||
## Validator assignments
|
## Validator assignments
|
||||||
|
|
||||||
|
@ -56,6 +75,8 @@ 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,
|
unknown parent. It cannot faithfully attest to the head block of the chain,
|
||||||
since it has not fully verified that block.
|
since it has not fully verified that block.
|
||||||
|
|
||||||
|
### Helpers
|
||||||
|
|
||||||
Let `head_block: BeaconBlock` be the result of calling of the fork choice
|
Let `head_block: BeaconBlock` be the result of calling of the fork choice
|
||||||
algorithm at the time of block production. Let `justified_block: BeaconBlock`
|
algorithm at the time of block production. Let `justified_block: BeaconBlock`
|
||||||
be the latest current justified ancestor ancestor of the `head_block`.
|
be the latest current justified ancestor ancestor of the `head_block`.
|
||||||
|
@ -75,8 +96,18 @@ def latest_valid_ancestor(block: BeaconBlock) -> Optional[BeaconBlock]:
|
||||||
return None
|
return None
|
||||||
```
|
```
|
||||||
|
|
||||||
Let a node which returns `is_optimistic(head) == True` be an *optimistic
|
```python
|
||||||
node*. Let a validator on an optimistic node be an *optimistic validator*.
|
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*.
|
||||||
|
|
||||||
### Block production
|
### Block production
|
||||||
|
|
||||||
|
@ -86,9 +117,11 @@ A optimistic validator MUST NOT produce a block (i.e., sign across the
|
||||||
#### Exception 1.
|
#### Exception 1.
|
||||||
|
|
||||||
If the justified block is fully verified (i.e., `not
|
If the justified block is fully verified (i.e., `not
|
||||||
is_optimistic(justified_block)`, the validator MUST produce a block upon
|
is_optimistic(justified_block)`, the validator MAY produce a block upon
|
||||||
`latest_valid_ancestor(head)`.
|
`latest_valid_ancestor(head)`.
|
||||||
|
|
||||||
|
If the latest valid ancestor is `None`, the validator MUST NOT produce a block.
|
||||||
|
|
||||||
### Attesting
|
### Attesting
|
||||||
|
|
||||||
An optimistic validator MUST NOT participate in attestation (i.e., sign across the
|
An optimistic validator MUST NOT participate in attestation (i.e., sign across the
|
||||||
|
@ -96,10 +129,20 @@ An optimistic validator MUST NOT participate in attestation (i.e., sign across t
|
||||||
`DOMAIN_AGGREGATE_AND_PROOF` domains), unless one of the follow exceptions are
|
`DOMAIN_AGGREGATE_AND_PROOF` domains), unless one of the follow exceptions are
|
||||||
met:
|
met:
|
||||||
|
|
||||||
#### Exception
|
|
||||||
|
|
||||||
#### Exception 1.
|
#### Exception 1.
|
||||||
|
|
||||||
If a validator *does not* have an optimistic head (i.e., `not
|
If the justified block is fully verified (i.e., `not
|
||||||
is_optimistic(head_block)`), the node is *fully synced*.
|
is_optimistic(justified_block)`, the validator MAY sign across the following
|
||||||
The validator may produce an attestation.
|
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).
|
||||||
|
|
Loading…
Reference in New Issue