Skip to content

Commit

Permalink
Update Bellatrix
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand committed Feb 16, 2024
1 parent 090ce85 commit 1a120e4
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
80 changes: 80 additions & 0 deletions docs/specs/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -870,3 +870,83 @@ As per EIP-3675, before a post-transition block is finalized, `notify_forkchoice

The `safe_block_hash` parameter MUST be set to return value of
[`get_safe_execution_payload_hash(store: Store)`](../../fork_choice/safe-block.md#get_safe_execution_payload_hash) function.

##### `should_override_forkchoice_update`

If proposer boost re-orgs are implemented and enabled (see `get_proposer_head`) then additional care
must be taken to ensure that the proposer is able to build an execution payload.

If a beacon node knows it will propose the next block then it SHOULD NOT call
`notify_forkchoice_updated` if it detects the current head to be weak and potentially capable of
being re-orged. Complete information for evaluating `get_proposer_head` _will not_ be available
immediately after the receipt of a new block, so an approximation of those conditions should be
used when deciding whether to send or suppress a fork choice notification. The exact conditions
used may be implementation-specific, a suggested implementation is below.

Let `validator_is_connected(validator_index: ValidatorIndex) -> bool` be a function that indicates
whether the validator with `validator_index` is connected to the node (e.g. has sent an unexpired
proposer preparation message).

```python
def should_override_forkchoice_update(store: Store, head_root: Root) -> bool:
head_block = store.blocks[head_root]
parent_root = head_block.parent_root
parent_block = store.blocks[parent_root]
current_slot = get_current_slot(store)
proposal_slot = head_block.slot + Slot(1)

# Only re-org the head_block block if it arrived later than the attestation deadline.
head_late = is_head_late(store, head_root)

# Shuffling stable.
shuffling_stable = is_shuffling_stable(proposal_slot)

# FFG information of the new head_block will be competitive with the current head.
ffg_competitive = is_ffg_competitive(store, head_root, parent_root)

# Do not re-org if the chain is not finalizing with acceptable frequency.
finalization_ok = is_finalization_ok(store, proposal_slot)

# Only suppress the fork choice update if we are confident that we will propose the next block.
parent_state_advanced = store.block_states[parent_root].copy()
process_slots(parent_state_advanced, proposal_slot)
proposer_index = get_beacon_proposer_index(parent_state_advanced)
proposing_reorg_slot = validator_is_connected(proposer_index)

# Single slot re-org.
parent_slot_ok = parent_block.slot + 1 == head_block.slot
proposing_on_time = is_proposing_on_time(store)

# Note that this condition is different from `get_proposer_head`
current_time_ok = (head_block.slot == current_slot
or (proposal_slot == current_slot and proposing_on_time))
single_slot_reorg = parent_slot_ok and current_time_ok

# Check the head weight only if the attestations from the head slot have already been applied.
# Implementations may want to do this in different ways, e.g. by advancing
# `store.time` early, or by counting queued attestations during the head block's slot.
if current_slot > head_block.slot:
head_weak = is_head_weak(store, head_root)
parent_strong = is_parent_strong(store, parent_root)
else:
head_weak = True
parent_strong = True

return all([head_late, shuffling_stable, ffg_competitive, finalization_ok,
proposing_reorg_slot, single_slot_reorg,
head_weak, parent_strong])
```

*Note*: The ordering of conditions is a suggestion only. Implementations are free to
optimize by re-ordering the conditions from least to most expensive and by returning early if
any of the early conditions are `False`.

In case `should_override_forkchoice_update` returns `True`, a node SHOULD instead call
`notify_forkchoice_updated` with parameters appropriate for building upon the parent block. Care
must be taken to compute the correct `payload_attributes`, as they may change depending on the slot
of the block to be proposed (due to withdrawals).

If `should_override_forkchoice_update` returns `True` but `get_proposer_head` later chooses the
canonical head rather than its parent, then this is a misprediction that will cause the node
to construct a payload with less notice. The result of `get_proposer_head` MUST be preferred over
the result of `should_override_forkchoice_update` (when proposer reorgs are enabled).
2 changes: 1 addition & 1 deletion docs/specs/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ Alias `block = signed_beacon_block.message`, `execution_payload = block.body.exe
then validate the following:
- _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot
-- i.e. `execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot)`.
- If `exection_payload` verification of block's parent by an execution node is *not* complete:
- If `execution_payload` verification of block's parent by an execution node is *not* complete:
- [REJECT] The block's parent (defined by `block.parent_root`) passes all
validation (excluding execution node verification of the `block.body.execution_payload`).
- otherwise:
Expand Down

0 comments on commit 1a120e4

Please sign in to comment.