Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bellatrix: pass justified as a safe block #2858

Merged
merged 9 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
31 changes: 31 additions & 0 deletions fork_choice/safe-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Fork Choice -- Safe Block
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that this file is cross forks. Maybe note that it is only valid post-Bellatrix.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In general, safe block algorithm can be implemented with Phase0 structures. I would add a note that get_safe_execution_payload_hash helper is based on Bellatrix


## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Introduction](#introduction)
- [`get_safe_beacon_block`](#get_safe_beacon_block)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Introduction

Under honest majority and certain network synchronicity assumptions
there exist a block that is safe from re-orgs. Normally this block is
pretty close to the head of canonical chain which makes it valuable
to expose a safe block to users.

This section describes an algorithm to find a safe block.

## `get_safe_beacon_block`

```python
def get_safe_beacon_block(store: Store) -> Root:
# Use most recent justified block as a stopgap
return store.justified_checkpoint.root
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
```
*Note*: Currently safe block algorithm simply returns `store.justified_checkpoint.root`
and is meant to be improved in the future.
18 changes: 17 additions & 1 deletion specs/bellatrix/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Protocols](#protocols)
- [`ExecutionEngine`](#executionengine)
- [`notify_forkchoice_updated`](#notify_forkchoice_updated)
- [`safe_block_hash`](#safe_block_hash)
- [Helpers](#helpers)
- [`PayloadAttributes`](#payloadattributes)
- [`PowBlock`](#powblock)
Expand Down Expand Up @@ -72,7 +73,22 @@ As per EIP-3675, before a post-transition block is finalized, `notify_forkchoice

*Note*: Client software MUST call this function to initiate the payload build process to produce the merge transition block; the `head_block_hash` parameter MUST be set to the hash of a terminal PoW block in this case.

*Note*: Until safe head function is implemented, `safe_block_hash` parameter MUST be stubbed with the `head_block_hash` value.
##### `safe_block_hash`

The `safe_block_hash` parameter in a call to `notify_forkchoice_updated` function
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
MUST be set to the return value of the following function:

```python
def get_safe_block_hash(store: Store) -> Hash32:
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should likely got in the safe_block helper file

safe_block_root = get_safe_beacon_block(store)
safe_block = store.blocks[safe_block_root]

# Return Hash32() if no payload is yet justified
if compute_epoch_at_slot(safe_block.slot) >= BELLATRIX_FORK_EPOCH:
return safe_block.body.execution_payload.block_hash
else:
return Hash32()
```

## Helpers

Expand Down
8 changes: 4 additions & 4 deletions specs/bellatrix/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,18 @@ All validator responsibilities remain unchanged other than those noted below. Na

To obtain an execution payload, a block proposer building a block on top of a `state` must take the following actions:

1. Set `payload_id = prepare_execution_payload(state, pow_chain, finalized_block_hash, suggested_fee_recipient, execution_engine)`, where:
1. Set `payload_id = prepare_execution_payload(state, pow_chain, finalized_block_hash, safe_block_hash, suggested_fee_recipient, execution_engine)`, where:
* `state` is the state object after applying `process_slots(state, slot)` transition to the resulting state of the parent block processing
* `pow_chain` is a `Dict[Hash32, PowBlock]` dictionary that abstractly represents all blocks in the PoW chain with block hash as the dictionary key
* `safe_block_hash` is the return value of the `get_safe_block_hash(store: Store)` function call
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
* `finalized_block_hash` is the hash of the latest finalized execution payload (`Hash32()` if none yet finalized)
* `suggested_fee_recipient` is the value suggested to be used for the `fee_recipient` field of the execution payload


```python
def prepare_execution_payload(state: BeaconState,
pow_chain: Dict[Hash32, PowBlock],
safe_block_hash: Hash32,
finalized_block_hash: Hash32,
suggested_fee_recipient: ExecutionAddress,
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
Expand All @@ -146,11 +148,9 @@ def prepare_execution_payload(state: BeaconState,
prev_randao=get_randao_mix(state, get_current_epoch(state)),
suggested_fee_recipient=suggested_fee_recipient,
)
# Set safe and head block hashes to the same value
return execution_engine.notify_forkchoice_updated(
head_block_hash=parent_hash,
# TODO: Use `parent_hash` as a stub for now.
safe_block_hash=parent_hash,
safe_block_hash=safe_block_hash,
finalized_block_hash=finalized_block_hash,
payload_attributes=payload_attributes,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def test_prepare_execution_payload(spec, state):

# Dummy arguments
finalized_block_hash = b'\x56' * 32
safe_block_hash = b'\x58' * 32
suggested_fee_recipient = b'\x78' * 20

# Mock execution_engine
Expand All @@ -158,6 +159,7 @@ def notify_forkchoice_updated(self,
state=state,
pow_chain=pow_chain.to_dict(),
finalized_block_hash=finalized_block_hash,
safe_block_hash=safe_block_hash,
suggested_fee_recipient=suggested_fee_recipient,
execution_engine=TestEngine(),
)
Expand Down