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

Release minor kintsugi update #2717

Merged
merged 16 commits into from
Nov 8, 2021
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
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload)
def notify_forkchoice_updated(self: ExecutionEngine,
head_block_hash: Hash32,
finalized_block_hash: Hash32,
payload_attributes: Optional[PayloadAttributes]) -> None:
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
pass

def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
Expand Down
14 changes: 11 additions & 3 deletions specs/merge/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Protocols](#protocols)
- [`ExecutionEngine`](#executionengine)
- [`notify_forkchoice_updated`](#notify_forkchoice_updated)
Expand All @@ -29,6 +30,12 @@ This is the modification of the fork choice according to the executable beacon c

*Note*: It introduces the process of transition from the last PoW block to the first PoS block.

## Custom types

| Name | SSZ equivalent | Description |
| - | - | - |
| `PayloadId` | `Bytes8` | Identifier of a payload building process |

## Protocols

### `ExecutionEngine`
Expand All @@ -46,13 +53,13 @@ This function performs two actions *atomically*:
and corresponding state, up to and including `finalized_block_hash`.

Additionally, if `payload_attributes` is provided, this function sets in motion a payload build process on top of
`head_block_hash` with the result to be gathered by a followup call to `get_payload`.
`head_block_hash` and returns an identifier of initiated process.

```python
def notify_forkchoice_updated(self: ExecutionEngine,
head_block_hash: Hash32,
finalized_block_hash: Hash32,
payload_attributes: Optional[PayloadAttributes]) -> None:
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
...
```

Expand Down Expand Up @@ -115,7 +122,8 @@ def validate_merge_block(block: BeaconBlock) -> None:
if TERMINAL_BLOCK_HASH != Hash32():
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
return block.block_hash == TERMINAL_BLOCK_HASH
assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
return

pow_block = get_pow_block(block.body.execution_payload.parent_hash)
# Check if `pow_block` is available
Expand Down
33 changes: 3 additions & 30 deletions specs/merge/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@

- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Custom types](#custom-types)
- [Helpers](#helpers)
- [`get_pow_block_at_terminal_total_difficulty`](#get_pow_block_at_terminal_total_difficulty)
- [`get_terminal_pow_block`](#get_terminal_pow_block)
- [`get_payload_id`](#get_payload_id)
- [Protocols](#protocols)
- [`ExecutionEngine`](#executionengine)
- [`get_payload`](#get_payload)
Expand All @@ -38,12 +36,6 @@ All behaviors and definitions defined in this document, and documents it extends
All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [The Merge](./beacon-chain.md) are requisite for this document and used throughout.
Please see related Beacon Chain doc before continuing and use them as a reference throughout.

## Custom types

| Name | SSZ equivalent | Description |
| - | - | - |
| `PayloadId` | `Bytes8` | Identifier of a payload building process |

## Helpers

### `get_pow_block_at_terminal_total_difficulty`
Expand Down Expand Up @@ -75,24 +67,6 @@ def get_terminal_pow_block(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlo
return get_pow_block_at_terminal_total_difficulty(pow_chain)
```

### `get_payload_id`

Given the `head_block_hash` and the `payload_attributes` that were used to
initiate the build process via `notify_forkchoice_updated`, `get_payload_id()`
returns the `payload_id` used to retrieve the payload via `get_payload`.

```python
def get_payload_id(parent_hash: Hash32, payload_attributes: PayloadAttributes) -> PayloadId:
return PayloadId(
hash(
parent_hash
+ uint_to_bytes(payload_attributes.timestamp)
+ payload_attributes.random
+ payload_attributes.fee_recipient
)[0:8]
)
```

*Note*: This function does *not* use simple serialize `hash_tree_root` as to
avoid requiring simple serialize hashing capabilities in the Execution Layer.

Expand Down Expand Up @@ -147,8 +121,8 @@ def prepare_execution_payload(state: BeaconState,
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
if not is_merge_complete(state):
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
is_activation_epoch_reached = get_current_epoch(state.slot) < TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
if is_terminal_block_hash_set and is_activation_epoch_reached:
is_activation_epoch_reached = get_current_epoch(state.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
if is_terminal_block_hash_set and not is_activation_epoch_reached:
# Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
return None

Expand All @@ -168,8 +142,7 @@ def prepare_execution_payload(state: BeaconState,
random=get_randao_mix(state, get_current_epoch(state)),
fee_recipient=fee_recipient,
)
execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
return get_payload_id(parent_hash, payload_attributes)
return execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
```

2. Set `block.body.execution_payload = get_execution_payload(payload_id, execution_engine)`, where:
Expand Down
2 changes: 1 addition & 1 deletion specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ Specifically a validator should:

## Beacon chain responsibilities

A validator has two primary responsibilities to the beacon chain: [proposing blocks](#block-proposal) and [creating attestations](#attestations-1). Proposals happen infrequently, whereas attestations should be created once per epoch.
A validator has two primary responsibilities to the beacon chain: [proposing blocks](#block-proposal) and [creating attestations](#attesting). Proposals happen infrequently, whereas attestations should be created once per epoch.

### Block proposal

Expand Down
2 changes: 1 addition & 1 deletion tests/core/pyspec/eth2spec/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.4
1.1.5
11 changes: 0 additions & 11 deletions tests/core/pyspec/eth2spec/test/helpers/fork_choice.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from random import Random
from eth_utils import encode_hex
from eth2spec.test.exceptions import BlockNotFoundException
from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.helpers.attestations import (
next_epoch_with_attestations,
next_slots_with_attestations,
Expand Down Expand Up @@ -247,15 +245,6 @@ def apply_next_slots_with_attestations(spec,
return post_state, store, last_signed_block


def prepare_empty_pow_block(spec, rng=Random(3131)):
return spec.PowBlock(
block_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
parent_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
total_difficulty=uint256(0),
difficulty=uint256(0)
)


def get_pow_block_file_name(pow_block):
return f"pow_block_{encode_hex(pow_block.block_hash)}"

Expand Down
34 changes: 34 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/pow_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from random import Random
from eth2spec.utils.ssz.ssz_typing import uint256


class PowChain:
blocks = []

def __init__(self, blocks):
self.blocks = blocks

def __iter__(self):
return iter(self.blocks)

def head(self, offset=0):
assert offset <= 0
return self.blocks[offset - 1]


def prepare_random_pow_block(spec, rng=Random(3131)):
return spec.PowBlock(
block_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
parent_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
total_difficulty=uint256(0),
difficulty=uint256(0)
)


def prepare_random_pow_chain(spec, length, rng=Random(3131)) -> PowChain:
assert length > 0
chain = [prepare_random_pow_block(spec, rng)]
for i in range(1, length):
chain.append(prepare_random_pow_block(spec, rng))
chain[i].parent_hash = chain[i - 1].block_hash
return PowChain(chain)
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
state_transition_and_sign_block,
)
from eth2spec.test.helpers.fork_choice import (
prepare_empty_pow_block,
add_pow_block,
)
from eth2spec.test.helpers.pow_block import (
prepare_random_pow_block,
)
from eth2spec.test.helpers.execution_payload import (
build_state_with_incomplete_transition,
)
Expand Down Expand Up @@ -58,9 +60,9 @@ def test_all_valid(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time

pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_blocks = [pow_block, pow_block_parent]
Expand Down Expand Up @@ -92,7 +94,7 @@ def test_block_lookup_failed(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time

pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_pow_block(spec)
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [pow_block]
for pb in pow_blocks:
Expand Down Expand Up @@ -122,9 +124,9 @@ def test_too_early_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time

pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [pow_block, pow_block_parent]
Expand Down Expand Up @@ -154,9 +156,9 @@ def test_too_late_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time

pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)
pow_blocks = [pow_block, pow_block_parent]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.helpers.pow_block import (
prepare_random_pow_block,
)
from eth2spec.test.context import (
spec_state_test,
with_merge_and_later,
)


@with_merge_and_later
@spec_state_test
def test_is_valid_terminal_pow_block_success_valid(spec, state):
parent_block = prepare_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
block = prepare_random_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY

assert spec.is_valid_terminal_pow_block(block, parent_block)


@with_merge_and_later
@spec_state_test
def test_is_valid_terminal_pow_block_fail_before_terminal(spec, state):
parent_block = prepare_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
block = prepare_random_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)

assert not spec.is_valid_terminal_pow_block(block, parent_block)


@with_merge_and_later
@spec_state_test
def test_is_valid_terminal_pow_block_fail_just_after_terminal(spec, state):
parent_block = prepare_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = prepare_random_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)

assert not spec.is_valid_terminal_pow_block(block, parent_block)
Loading