Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
djrtwo committed Oct 15, 2021
2 parents 6ef79b1 + 7f41f18 commit 0eb3a86
Show file tree
Hide file tree
Showing 15 changed files with 970 additions and 155 deletions.
3 changes: 0 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,9 +527,6 @@ class NoopExecutionEngine(ExecutionEngine):
def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
return True
def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None:
pass
def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None:
pass
Expand Down
29 changes: 5 additions & 24 deletions specs/merge/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
- [Execution engine](#execution-engine)
- [`execute_payload`](#execute_payload)
- [`notify_consensus_validated`](#notify_consensus_validated)
- [Block processing](#block-processing)
- [Execution payload processing](#execution-payload-processing)
- [`is_valid_gas_limit`](#is_valid_gas_limit)
Expand Down Expand Up @@ -145,8 +144,6 @@ class BeaconState(Container):

#### `ExecutionPayload`

*Note*: The `base_fee_per_gas` field is serialized in little-endian.

```python
class ExecutionPayload(Container):
# Execution block header fields
Expand All @@ -161,7 +158,7 @@ class ExecutionPayload(Container):
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: Bytes32 # base fee introduced in EIP-1559, little-endian serialized
base_fee_per_gas: uint256
# Extra payload fields
block_hash: Hash32 # Hash of execution block
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
Expand All @@ -183,7 +180,7 @@ class ExecutionPayloadHeader(Container):
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: Bytes32
base_fee_per_gas: uint256
# Extra payload fields
block_hash: Hash32 # Hash of execution block
transactions_root: Root
Expand Down Expand Up @@ -234,13 +231,11 @@ The implementation-dependent `ExecutionEngine` protocol encapsulates the executi

* a state object `self.execution_state` of type `ExecutionState`
* a state transition function `self.execute_payload` which applies changes to the `self.execution_state`
* a function `self.notify_consensus_validated` which signals that the beacon block containing the execution payload
is valid with respect to the consensus rule set

*Note*: `execute_payload` and `notify_consensus_validated` are functions accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.
*Note*: `execute_payload` is a function accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.

The body of each of these functions is implementation dependent.
The Engine API may be used to implement them with an external execution engine.
The body of this function is implementation dependent.
The Engine API may be used to implement this and similarly defined functions via an external execution engine.

#### `execute_payload`

Expand All @@ -252,20 +247,6 @@ def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload)
...
```

#### `notify_consensus_validated`

```python
def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None:
...
```

The inputs to this function depend on the result of the state transition. A call to `notify_consensus_validated` must be made after the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows:

* `True` if `state_transition` function call succeeds
* `False` if `state_transition` function call fails

*Note*: The call of the `notify_consensus_validated` function with `valid = True` maps on the `POS_CONSENSUS_VALIDATED` event defined in the [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#definitions).

### Block processing

*Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block.
Expand Down
2 changes: 1 addition & 1 deletion specs/merge/client-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This document specifies configurable settings that clients must implement for th

### Override terminal total difficulty

To coordinate manual overrides to [`TERMINAL_TOTAL_DIFFICULTY`](./beacon-chain.md#Transition-settings) parameter, clients must provide `--terminal-total-difficulty-override` as a configurable setting. The value provided by this setting must take precedence over pre-configured `TERMINAL_TOTAL_DIFFICULTY` parameter.
To coordinate manual overrides to [`TERMINAL_TOTAL_DIFFICULTY`](./beacon-chain.md#Transition-settings) parameter, clients must provide `--terminal-total-difficulty-override` as a configurable setting. The value provided by this setting must take precedence over pre-configured `TERMINAL_TOTAL_DIFFICULTY` parameter. Clients should accept the setting as a decimal value (i.e., *not* hexadecimal).

Except under exceptional scenarios, this setting is expected to not be used. Sufficient warning to the user about this exceptional configurable setting should be provided.

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.2
1.1.3
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from random import Random

from eth2spec.test.context import spec_state_test, with_altair_and_later
from eth2spec.test.helpers.inactivity_scores import randomize_inactivity_scores, zero_inactivity_scores
from eth2spec.test.helpers.inactivity_scores import (
randomize_inactivity_scores,
zero_inactivity_scores,
)
from eth2spec.test.helpers.state import (
next_epoch,
next_epoch_via_block,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import random
from eth2spec.test.context import (
MINIMAL,
fork_transition_test,
with_presets,
)
from eth2spec.test.helpers.constants import PHASE0, ALTAIR
from eth2spec.test.helpers.fork_transition import (
do_altair_fork,
transition_until_fork,
transition_to_next_epoch_and_append_blocks,
)
from eth2spec.test.helpers.random import (
exit_random_validators,
set_some_activations,
set_some_new_deposits,
)


#
# Exit
#

@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2)
@with_presets([MINIMAL],
reason="only test with enough validators such that at least one exited index is not in sync committee")
def test_transition_with_one_fourth_exiting_validators_exit_post_fork(state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag):
"""
1/4 validators initiated voluntary exit before the fork,
and are exiting but still active *after* the fork transition.
"""
exited_indices = exit_random_validators(
spec,
state,
rng=random.Random(5566),
fraction=0.25,
exit_epoch=10,
from_epoch=spec.get_current_epoch(state),
)

transition_until_fork(spec, state, fork_epoch)

# check pre state
assert len(exited_indices) > 0
for index in exited_indices:
validator = state.validators[index]
assert not validator.slashed
assert fork_epoch < validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(validator, spec.get_current_epoch(state))
assert not spec.is_in_inactivity_leak(state)
assert spec.get_current_epoch(state) < fork_epoch

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# ensure that some of the current sync committee members are exiting
exited_pubkeys = [state.validators[index].pubkey for index in exited_indices]
assert any(set(exited_pubkeys).intersection(list(state.current_sync_committee.pubkeys)))
assert any(set(exited_pubkeys).difference(list(state.current_sync_committee.pubkeys)))

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

# check state
for index in exited_indices:
validator = state.validators[index]
assert not validator.slashed
assert post_spec.is_active_validator(validator, post_spec.get_current_epoch(state))
assert not post_spec.is_in_inactivity_leak(state)

yield "blocks", blocks
yield "post", state


@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2)
def test_transition_with_one_fourth_exiting_validators_exit_at_fork(state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag):
"""
1/4 validators initiated voluntary exit before the fork,
and being exited and inactive *right after* the fork transition.
"""
exited_indices = exit_random_validators(
spec,
state,
rng=random.Random(5566),
fraction=0.25,
exit_epoch=fork_epoch,
from_epoch=spec.get_current_epoch(state),
)

transition_until_fork(spec, state, fork_epoch)

# check pre state
assert len(exited_indices) > 0
for index in exited_indices:
validator = state.validators[index]
assert not validator.slashed
assert fork_epoch == validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(validator, spec.get_current_epoch(state))
assert not spec.is_in_inactivity_leak(state)
assert spec.get_current_epoch(state) < fork_epoch

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# check post transition state
for index in exited_indices:
validator = state.validators[index]
assert not validator.slashed
assert not post_spec.is_active_validator(validator, post_spec.get_current_epoch(state))
assert not post_spec.is_in_inactivity_leak(state)

# ensure that none of the current sync committee members are exited validators
exited_pubkeys = [state.validators[index].pubkey for index in exited_indices]
assert not any(set(exited_pubkeys).intersection(list(state.current_sync_committee.pubkeys)))

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

yield "blocks", blocks
yield "post", state


#
# Activation
#


@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2)
def test_transition_with_non_empty_activation_queue(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
"""
Create some deposits before the transition
"""
transition_until_fork(spec, state, fork_epoch)

deposited_indices = set_some_new_deposits(spec, state, rng=random.Random(5566))

assert spec.get_current_epoch(state) < fork_epoch
assert len(deposited_indices) > 0
for validator_index in deposited_indices:
assert not spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state))

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

yield "blocks", blocks
yield "post", state


@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2)
def test_transition_with_activation_at_fork_epoch(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
"""
Create some deposits before the transition
"""
transition_until_fork(spec, state, fork_epoch)

selected_indices = set_some_activations(spec, state, rng=random.Random(5566), activation_epoch=fork_epoch)

assert spec.get_current_epoch(state) < fork_epoch
assert len(selected_indices) > 0
for validator_index in selected_indices:
validator = state.validators[validator_index]
assert not spec.is_active_validator(validator, spec.get_current_epoch(state))
assert validator.activation_epoch == fork_epoch

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

# now they are active
for validator_index in selected_indices:
validator = state.validators[validator_index]
assert post_spec.is_active_validator(validator, post_spec.get_current_epoch(state))

yield "blocks", blocks
yield "post", state
63 changes: 63 additions & 0 deletions tests/core/pyspec/eth2spec/test/altair/transition/test_leaking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from eth2spec.test.context import fork_transition_test
from eth2spec.test.helpers.constants import PHASE0, ALTAIR
from eth2spec.test.helpers.fork_transition import (
do_altair_fork,
transition_until_fork,
transition_to_next_epoch_and_append_blocks,
)


@fork_transition_test(PHASE0, ALTAIR, fork_epoch=7)
def test_transition_with_leaking_pre_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
"""
Leaking starts at epoch 6 (MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2).
The leaking starts before the fork transition in this case.
"""
transition_until_fork(spec, state, fork_epoch)

assert spec.is_in_inactivity_leak(state)
assert spec.get_current_epoch(state) < fork_epoch

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# check post transition state
assert spec.is_in_inactivity_leak(state)

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

yield "blocks", blocks
yield "post", state


@fork_transition_test(PHASE0, ALTAIR, fork_epoch=6)
def test_transition_with_leaking_at_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
"""
Leaking starts at epoch 6 (MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2).
The leaking starts at the fork transition in this case.
"""
transition_until_fork(spec, state, fork_epoch)

assert not spec.is_in_inactivity_leak(state)
assert spec.get_current_epoch(state) < fork_epoch

yield "pre", state

# irregular state transition to handle fork:
blocks = []
state, block = do_altair_fork(state, spec, post_spec, fork_epoch)
blocks.append(post_tag(block))

# check post transition state
assert spec.is_in_inactivity_leak(state)

# continue regular state transition with new spec into next epoch
transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True)

yield "blocks", blocks
yield "post", state
Loading

0 comments on commit 0eb3a86

Please sign in to comment.