Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions specs/gloas/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
- [Modified `get_forkchoice_store`](#modified-get_forkchoice_store)
- [New `notify_ptc_messages`](#new-notify_ptc_messages)
- [New `is_payload_verified`](#new-is_payload_verified)
- [New `is_payload_timely`](#new-is_payload_timely)
- [New `is_payload_data_available`](#new-is_payload_data_available)
- [New `payload_timeliness`](#new-payload_timeliness)
- [New `payload_data_availability`](#new-payload_data_availability)
- [New `get_parent_payload_status`](#new-get_parent_payload_status)
- [New `is_parent_node_full`](#new-is_parent_node_full)
- [Modified `get_ancestor`](#modified-get_ancestor)
- [Modified `get_checkpoint_block`](#modified-get_checkpoint_block)
- [New `is_supporting_vote`](#new-is_supporting_vote)
- [New `should_build_on_full`](#new-should_build_on_full)
- [New `should_extend_payload`](#new-should_extend_payload)
- [New `get_payload_status_tiebreaker`](#new-get_payload_status_tiebreaker)
- [New `should_apply_proposer_boost`](#new-should_apply_proposer_boost)
Expand Down Expand Up @@ -262,44 +263,46 @@ def is_payload_verified(store: Store, root: Root) -> bool:
return root in store.payloads
```

### New `is_payload_timely`
### New `payload_timeliness`

```python
def is_payload_timely(store: Store, root: Root) -> bool:
def payload_timeliness(store: Store, root: Root, timely: bool) -> bool:
"""
Return whether the execution payload for the beacon block with root ``root``
was voted as present by the PTC, and was locally determined to be available.
is considered ``timely`` (or not, when ``timely`` is ``False``), taking into
consideration local availability and PTC votes.
"""
# The beacon block root must be known
assert root in store.payload_timeliness_vote

# If the payload is not locally available, the payload
# is not considered available regardless of the PTC vote
if not is_payload_verified(store, root):
return False
return not timely

votes = store.payload_timeliness_vote[root]
return sum(vote is True for vote in votes) > PAYLOAD_TIMELY_THRESHOLD
return sum(vote is timely for vote in votes) > PAYLOAD_TIMELY_THRESHOLD
```

### New `is_payload_data_available`
### New `payload_data_availability`

```python
def is_payload_data_available(store: Store, root: Root) -> bool:
def payload_data_availability(store: Store, root: Root, available: bool) -> bool:
"""
Return whether the blob data for the beacon block with root ``root``
was voted as present by the PTC, and was locally determined to be available.
Return whether the blob data for the beacon block with root ``root`` is
considered ``available`` (or not, when ``available`` is ``False``), taking into
consideration local availability and PTC votes.
"""
# The beacon block root must be known
assert root in store.payload_data_availability_vote

# If the payload is not locally available, the blob data
# is not considered available regardless of the PTC vote
if not is_payload_verified(store, root):
return False
return not available

votes = store.payload_data_availability_vote[root]
return sum(vote is True for vote in votes) > DATA_AVAILABILITY_TIMELY_THRESHOLD
return sum(vote is available for vote in votes) > DATA_AVAILABILITY_TIMELY_THRESHOLD
```

### New `get_parent_payload_status`
Expand Down Expand Up @@ -386,6 +389,21 @@ def is_supporting_vote(store: Store, node: ForkChoiceNode, message: LatestMessag
)
```

### New `should_build_on_full`

*Note*: `should_build_on_full` is called by the proposer before deciding whether
to build on top of the empty or full parent pending node. This function is
similar to `should_extend_payload` but takes into consideration the PTC view on
data availability.

```python
def should_build_on_full(store: Store, head: ForkChoiceNode) -> bool:
assert head.payload_status != PAYLOAD_STATUS_PENDING
if head.payload_status == PAYLOAD_STATUS_EMPTY:
return False
return not payload_data_availability(store, head.root, available=False)
```

### New `should_extend_payload`

*Note*: `should_extend_payload` decides whether to extend an available payload
Expand All @@ -400,8 +418,10 @@ def should_extend_payload(store: Store, root: Root) -> bool:
if not is_payload_verified(store, root):
return False
proposer_root = store.proposer_boost_root
payload_is_timely = payload_timeliness(store, root, timely=True)
payload_data_is_available = payload_data_availability(store, root, available=True)
return (
(is_payload_timely(store, root) and is_payload_data_available(store, root))
(payload_is_timely and payload_data_is_available)
or proposer_root == Root()
or store.blocks[proposer_root].parent_root != root
or is_parent_node_full(store, store.blocks[proposer_root])
Expand Down
28 changes: 16 additions & 12 deletions specs/gloas/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,29 +231,34 @@ construct the `payload_attestations` field in `BeaconBlockBody`:
##### Parent execution requests

The `parent_execution_requests` field contains the execution requests from the
parent's execution payload. The proposer constructs this field as follows:
parent's execution payload. Let `head = get_head(store)`. The proposer
constructs this field as follows:

- If the parent block is pre-Gloas (first Gloas block), set
`parent_execution_requests` to an empty `ExecutionRequests()`.
- If `should_extend_payload(store, block.parent_root)` is true (the proposer is
- If `should_build_on_full(store, head)` returns `True` (the proposer is
building on the parent's full payload), set `parent_execution_requests` to
`store.payloads[block.parent_root].execution_requests`.
`store.payloads[head.root].execution_requests`.
- Otherwise (the proposer is building on the parent's empty variant), set
`parent_execution_requests` to an empty `ExecutionRequests()`.

##### ExecutionPayload

*Note*: `prepare_execution_payload` is modified in Gloas to take `store` as an
additional parameter. It consults `should_extend_payload` to decide whether to
build on the parent's full payload or its empty variant, selecting both the
withdrawals source and the execution head for the new payload. When building on
a full parent, `apply_parent_execution_payload` is called so that withdrawals
are computed against the post-processing state.
*Note*: `prepare_execution_payload` is modified in Gloas to take `store` and
`head` as additional parameters. `head` is the return value of `get_head(store)`
and must correspond to the parent that `state` was derived from. It consults
`should_build_on_full(store, head)` to decide whether to build on the parent's
full payload or its empty variant, selecting both the withdrawals source and the
execution head for the new payload. When building on a full parent,
`apply_parent_execution_payload` is called so that withdrawals are computed
against the post-processing state.

```python
def prepare_execution_payload(
# [New in Gloas:EIP7732]
store: Store,
# [New in Gloas:EIP7732]
head: ForkChoiceNode,
state: BeaconState,
safe_block_hash: Hash32,
finalized_block_hash: Hash32,
Expand All @@ -262,9 +267,8 @@ def prepare_execution_payload(
) -> Optional[PayloadId]:
# [New in Gloas:EIP7732]
parent_bid = state.latest_execution_payload_bid
parent_root = hash_tree_root(state.latest_block_header)
if should_extend_payload(store, parent_root):
envelope = store.payloads[parent_root]
if should_build_on_full(store, head):
envelope = store.payloads[head.root]
Comment thread
jtraglia marked this conversation as resolved.
# Make a copy of the state to avoid mutability issues
state = copy(state)
# Apply parent payload before computing withdrawals
Expand Down
4 changes: 3 additions & 1 deletion specs/heze/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,10 @@ def should_extend_payload(store: Store, root: Root) -> bool:
if not is_payload_inclusion_list_satisfied(store, root):
return False
proposer_root = store.proposer_boost_root
payload_is_timely = payload_timeliness(store, root, timely=True)
payload_data_is_available = payload_data_availability(store, root, available=True)
return (
(is_payload_timely(store, root) and is_payload_data_available(store, root))
(payload_is_timely and payload_data_is_available)
or proposer_root == Root()
or store.blocks[proposer_root].parent_root != root
or is_parent_node_full(store, store.blocks[proposer_root])
Expand Down
6 changes: 3 additions & 3 deletions specs/heze/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,16 @@ inclusion lists they have observed.
```python
def prepare_execution_payload(
store: Store,
head: ForkChoiceNode,
state: BeaconState,
safe_block_hash: Hash32,
finalized_block_hash: Hash32,
suggested_fee_recipient: ExecutionAddress,
execution_engine: ExecutionEngine,
) -> Optional[PayloadId]:
parent_bid = state.latest_execution_payload_bid
parent_root = hash_tree_root(state.latest_block_header)
if should_extend_payload(store, parent_root):
envelope = store.payloads[parent_root]
if should_build_on_full(store, head):
envelope = store.payloads[head.root]
# Make a copy of the state to avoid mutability issues
state = copy(state)
# Apply parent payload before computing withdrawals
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def test_prepare_execution_payload__extend_payload(spec, state):
parent_bid = proposal_state.latest_execution_payload_bid
payload_id = spec.prepare_execution_payload(
store=store,
head=spec.get_head(store),
state=proposal_state,
safe_block_hash=spec.Hash32(),
finalized_block_hash=spec.Hash32(),
Expand Down Expand Up @@ -181,6 +182,7 @@ def test_prepare_execution_payload__no_payload_verified(spec, state):
parent_bid = proposal_state.latest_execution_payload_bid
payload_id = spec.prepare_execution_payload(
store=store,
head=spec.get_head(store),
state=proposal_state,
safe_block_hash=spec.Hash32(),
finalized_block_hash=spec.Hash32(),
Expand All @@ -204,6 +206,7 @@ def test_prepare_execution_payload__extend_payload_does_not_mutate_state(spec, s
engine = CaptureEngine()
spec.prepare_execution_payload(
store=store,
head=spec.get_head(store),
state=proposal_state,
safe_block_hash=spec.Hash32(),
finalized_block_hash=spec.Hash32(),
Expand All @@ -223,6 +226,7 @@ def test_prepare_execution_payload__payload_attributes(spec, state):
engine = CaptureEngine()
spec.prepare_execution_payload(
store=store,
head=spec.get_head(store),
state=proposal_state,
safe_block_hash=spec.Hash32(),
finalized_block_hash=spec.Hash32(),
Expand Down Expand Up @@ -253,6 +257,7 @@ def test_prepare_execution_payload__block_passes_state_transition(spec, state):
engine = CaptureEngine()
spec.prepare_execution_payload(
store=store,
head=spec.get_head(store),
state=proposal_state,
safe_block_hash=spec.Hash32(),
finalized_block_hash=spec.Hash32(),
Expand Down