Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
28 changes: 28 additions & 0 deletions specs/gloas/fast-confirmation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Gloas -- Fast Confirmation

<!-- mdformat-toc start --slug=github --no-anchors --maxlevel=6 --minlevel=2 -->

- [Introduction](#introduction)
- [Helpers](#helpers)
- [Modified `get_block_root_node`](#modified-get_block_root_node)

<!-- mdformat-toc end -->

## Introduction

This is the modification of the fast confirmation rule specification
accompanying Gloas.

## Helpers

### Modified `get_block_root_node`

*Note:* This function is modified to return an extended `ForkChoiceNode`
structure with `PAYLOAD_STATUS_PENDING` payload status as a common ancestor of
all nodes referring to a given `block_root`.

```python
def get_block_root_node(block_root: Root) -> ForkChoiceNode:
# [Modified in Gloas:EIP7732]
return ForkChoiceNode(root=block_root, payload_status=PAYLOAD_STATUS_PENDING)
```
13 changes: 0 additions & 13 deletions specs/gloas/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
- [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_block_root_node`](#modified-get_block_root_node)
- [Modified `get_ancestor`](#modified-get_ancestor)
- [Modified `is_ancestor`](#modified-is_ancestor)
- [Modified `get_checkpoint_block`](#modified-get_checkpoint_block)
Expand Down Expand Up @@ -328,18 +327,6 @@ def is_parent_node_full(store: Store, block: BeaconBlock) -> bool:
return get_parent_payload_status(store, block) == PAYLOAD_STATUS_FULL
```

### Modified `get_block_root_node`

*Note:* This function is modified to return an extended `ForkChoiceNode`
structure with `PAYLOAD_STATUS_PENDING` payload status as a common ancestor of
all nodes referring to a given `block_root`.

```python
def get_block_root_node(block_root: Root) -> ForkChoiceNode:
# [Modified in Gloas:EIP7732]
return ForkChoiceNode(root=block_root, payload_status=PAYLOAD_STATUS_PENDING)
```

### Modified `get_ancestor`

*Note*: `get_ancestor` is modified to return whether the chain is based on an
Expand Down
16 changes: 16 additions & 0 deletions specs/phase0/fast-confirmation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [`FastConfirmationStore`](#fastconfirmationstore)
- [`get_fast_confirmation_store`](#get_fast_confirmation_store)
- [Misc helper functions](#misc-helper-functions)
- [`get_block_root_node`](#get_block_root_node)
- [`get_block_slot`](#get_block_slot)
- [`get_block_epoch`](#get_block_epoch)
- [`get_checkpoint_for_block`](#get_checkpoint_for_block)
Expand Down Expand Up @@ -136,6 +137,21 @@ def get_fast_confirmation_store(store: Store) -> FastConfirmationStore:

#### Misc helper functions

#### `get_block_root_node`

*Note:* The semantics of this function is to construct a `ForkChoiceNode` that
is a common ancestor for all fork choice nodes referring to the same beacon
block. Future protocol versions may introduce new types of nodes, but this
function assumes that the common ancestor node type will always exist. This
function is introduced for future compatibility, it allows fast confirmation
rule code that operates over beacon blocks to be agnostic to the protocol
version.

```python
def get_block_root_node(block_root: Root) -> ForkChoiceNode:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great!

I would remove the note and rename to get_node_for_root. In this scenario, I would make sure this replaces inline constructions for default payloads in gloas

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lmk, if this now looks good to you. I personally think it’s a better way of handling default payload status than how it is done in the original PR. Also, get_node_for_root is a much better name to me

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you for the changes

return ForkChoiceNode(root=block_root)
```

##### `get_block_slot`

```python
Expand Down
15 changes: 0 additions & 15 deletions specs/phase0/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
- [`get_current_slot`](#get_current_slot)
- [`get_current_store_epoch`](#get_current_store_epoch)
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start)
- [`get_block_root_node`](#get_block_root_node)
- [`get_ancestor`](#get_ancestor)
- [`is_ancestor`](#is_ancestor)
- [`calculate_committee_fraction`](#calculate_committee_fraction)
Expand Down Expand Up @@ -263,20 +262,6 @@ def compute_slots_since_epoch_start(slot: Slot) -> int:
return slot - compute_start_slot_at_epoch(compute_epoch_at_slot(slot))
```

#### `get_block_root_node`

*Note:* The semantics of this function is to construct a `ForkChoiceNode` that
is a common ancestor for all fork choice nodes referring to the same beacon
block. Future protocol versions may introduce new types of nodes, but this
function assumes that the common ancestor node type will always exist. This
function is introduced for future compatibility, it allows the specification
code that operates over beacon blocks to be agnostic to the protocol version.

```python
def get_block_root_node(block_root: Root) -> ForkChoiceNode:
return ForkChoiceNode(root=block_root)
```

#### `get_ancestor`

```python
Expand Down
15 changes: 12 additions & 3 deletions tests/core/pyspec/eth_consensus_specs/test/helpers/fork_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ def wrap(flag: AtomicBoolean):
assert is_called.value


def get_fork_choice_node(spec, root, payload_status=None):
if is_post_gloas(spec):
if payload_status is None:
payload_status = spec.PAYLOAD_STATUS_PENDING
return spec.ForkChoiceNode(root=root, payload_status=payload_status)
else:
return spec.ForkChoiceNode(root=root)


def get_anchor_root(spec, state):
anchor_block_header = state.latest_block_header.copy()
if anchor_block_header.state_root == spec.Bytes32():
Expand Down Expand Up @@ -583,7 +592,7 @@ def get_weighed_node_checks(spec, store, node):

def get_viable_for_head_checks(spec, store):
filtered_blocks = spec.get_filtered_block_tree(store)
root_node = spec.get_block_root_node(store.justified_checkpoint.root)
root_node = get_fork_choice_node(spec, store.justified_checkpoint.root)
pending_nodes = [root_node]
leaves_viable_for_head = []

Expand Down Expand Up @@ -689,11 +698,11 @@ def is_ancestor(spec, store, root_or_node, maybe_ancestor_root_or_node) -> bool:
if hasattr(root_or_node, "root"):
node = root_or_node
else:
node = spec.get_block_root_node(root_or_node)
node = get_fork_choice_node(spec, root_or_node)

if hasattr(maybe_ancestor_root_or_node, "root"):
maybe_ancestor = maybe_ancestor_root_or_node
else:
maybe_ancestor = spec.get_block_root_node(maybe_ancestor_root_or_node)
maybe_ancestor = get_fork_choice_node(spec, maybe_ancestor_root_or_node)

return spec.is_ancestor(store, node, maybe_ancestor)
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
add_attestation,
add_block,
check_head_against_root,
get_fork_choice_node,
get_genesis_forkchoice_store_and_block,
on_tick_and_append_step,
tick_and_add_block,
Expand Down Expand Up @@ -117,7 +118,7 @@ def _get_greater_than_proposer_boost_score(spec, store, state, proposer_boost_ro
block = store.blocks[root]
proposer_score = 0
if (
spec.get_ancestor(store, spec.get_block_root_node(root), block.slot).root
spec.get_ancestor(store, get_fork_choice_node(spec, root), block.slot).root
== proposer_boost_root
):
num_validators = len(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
apply_next_slots_with_attestations,
check_head_against_root,
find_next_justifying_slot,
get_fork_choice_node,
get_genesis_forkchoice_store_and_block,
is_ready_to_justify,
on_tick_and_append_step,
Expand Down Expand Up @@ -524,7 +525,7 @@ def test_proposer_boost(spec, state):
on_tick_and_append_step(spec, store, time, test_steps)
yield from add_block(spec, store, signed_block, test_steps)
assert store.proposer_boost_root == spec.hash_tree_root(block)
node = spec.get_block_root_node(spec.hash_tree_root(block))
node = get_fork_choice_node(spec, spec.hash_tree_root(block))
assert spec.get_weight(store, node) > 0

# Ensure that boost is removed after slot is over
Expand All @@ -535,7 +536,7 @@ def test_proposer_boost(spec, state):
)
on_tick_and_append_step(spec, store, time, test_steps)
assert store.proposer_boost_root == spec.Root()
node = spec.get_block_root_node(spec.hash_tree_root(block))
node = get_fork_choice_node(spec, spec.hash_tree_root(block))
assert spec.get_weight(store, node) == 0

next_slots(spec, state, 3)
Expand All @@ -547,7 +548,7 @@ def test_proposer_boost(spec, state):
on_tick_and_append_step(spec, store, time, test_steps)
yield from add_block(spec, store, signed_block, test_steps)
assert store.proposer_boost_root == spec.hash_tree_root(block)
node = spec.get_block_root_node(spec.hash_tree_root(block))
node = get_fork_choice_node(spec, spec.hash_tree_root(block))
assert spec.get_weight(store, node) > 0

# Ensure that boost is removed after slot is over
Expand All @@ -558,7 +559,7 @@ def test_proposer_boost(spec, state):
)
on_tick_and_append_step(spec, store, time, test_steps)
assert store.proposer_boost_root == spec.Root()
node = spec.get_block_root_node(spec.hash_tree_root(block))
node = get_fork_choice_node(spec, spec.hash_tree_root(block))
assert spec.get_weight(store, node) == 0

test_steps.append(
Expand Down Expand Up @@ -646,7 +647,7 @@ def test_proposer_boost_is_first_block(spec, state):
yield from add_block(spec, store, signed_block_a, test_steps)
# `proposer_boost_root` is now `block_a`
assert store.proposer_boost_root == spec.hash_tree_root(block_a)
node_a = spec.get_block_root_node(spec.hash_tree_root(block_a))
node_a = get_fork_choice_node(spec, spec.hash_tree_root(block_a))
assert spec.get_weight(store, node_a) > 0
test_steps.append(
{
Expand All @@ -664,7 +665,7 @@ def test_proposer_boost_is_first_block(spec, state):
yield from add_block(spec, store, signed_block_b, test_steps)
# `proposer_boost_root` is still `block_a`
assert store.proposer_boost_root == spec.hash_tree_root(block_a)
node_b = spec.get_block_root_node(spec.hash_tree_root(block_b))
node_b = get_fork_choice_node(spec, spec.hash_tree_root(block_b))
assert spec.get_weight(store, node_b) == 0
test_steps.append(
{
Expand Down Expand Up @@ -1220,7 +1221,7 @@ def test_justified_update_not_realized_finality(spec, state):
last_block = signed_blocks[-1]
last_block_root = last_block.message.hash_tree_root()
ancestor_at_finalized_slot = spec.get_ancestor(
store, spec.get_block_root_node(last_block_root), finalized_block.slot
store, get_fork_choice_node(spec, last_block_root), finalized_block.slot
).root

assert ancestor_at_finalized_slot == store.finalized_checkpoint.root
Expand Down Expand Up @@ -1301,7 +1302,7 @@ def test_justified_update_monotonic(spec, state):
last_block = signed_blocks[-1]
last_block_root = last_block.message.hash_tree_root()
ancestor_at_finalized_slot = spec.get_ancestor(
store, spec.get_block_root_node(last_block_root), finalized_block.slot
store, get_fork_choice_node(spec, last_block_root), finalized_block.slot
).root
assert ancestor_at_finalized_slot == finalized_root

Expand Down