Skip to content

Commit

Permalink
Merge pull request #2733 from ethereum/dev
Browse files Browse the repository at this point in the history
 minor Merge and forkchoice updates release
  • Loading branch information
djrtwo authored Nov 24, 2021
2 parents 58b291b + cebc514 commit c81c27e
Show file tree
Hide file tree
Showing 38 changed files with 1,355 additions and 348 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ install_test:
# Testing against `minimal` config by default
test: pyspec
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.merge.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec

# Testing against `minimal` config by default
find_test: pyspec
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.merge.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec

citest: pyspec
mkdir -p tests/core/pyspec/test-reports/eth2spec;
Expand Down
5 changes: 5 additions & 0 deletions configs/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4
CHURN_LIMIT_QUOTIENT: 65536


# Fork choice
# ---------------------------------------------------------------
# 70%
PROPOSER_SCORE_BOOST: 70

# Deposit contract
# ---------------------------------------------------------------
# Ethereum PoW Mainnet
Expand Down
6 changes: 6 additions & 0 deletions configs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4
CHURN_LIMIT_QUOTIENT: 32


# Fork choice
# ---------------------------------------------------------------
# 70%
PROPOSER_SCORE_BOOST: 70


# Deposit contract
# ---------------------------------------------------------------
# Ethereum Goerli testnet
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def sundry_functions(cls) -> str:
def get_pow_block(hash: Bytes32) -> Optional[PowBlock]:
return PowBlock(block_hash=hash, parent_hash=Bytes32(), total_difficulty=uint256(0), difficulty=uint256(0))
return PowBlock(block_hash=hash, parent_hash=Bytes32(), total_difficulty=uint256(0))
def get_execution_state(execution_state_root: Bytes32) -> ExecutionState:
Expand Down
2 changes: 1 addition & 1 deletion specs/altair/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ This helper function is only for initializing the state for pure Altair testnets
*Note*: The function `initialize_beacon_state_from_eth1` is modified: (1) using `ALTAIR_FORK_VERSION` as the current fork version, (2) utilizing the Altair `BeaconBlockBody` when constructing the initial `latest_block_header`, and (3) adding initial sync committees.

```python
def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
eth1_timestamp: uint64,
deposits: Sequence[Deposit]) -> BeaconState:
fork = Fork(
Expand Down
26 changes: 13 additions & 13 deletions specs/merge/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
- [`ExecutionPayloadHeader`](#executionpayloadheader)
- [Helper functions](#helper-functions)
- [Predicates](#predicates)
- [`is_merge_complete`](#is_merge_complete)
- [`is_merge_block`](#is_merge_block)
- [`is_merge_transition_complete`](#is_merge_transition_complete)
- [`is_merge_transition_block`](#is_merge_transition_block)
- [`is_execution_enabled`](#is_execution_enabled)
- [Misc](#misc)
- [`compute_timestamp_at_slot`](#compute_timestamp_at_slot)
Expand Down Expand Up @@ -167,7 +167,7 @@ class BeaconState(Container):
class ExecutionPayload(Container):
# Execution block header fields
parent_hash: Hash32
coinbase: ExecutionAddress # 'beneficiary' in the yellow paper
fee_recipient: ExecutionAddress # 'beneficiary' in the yellow paper
state_root: Bytes32
receipt_root: Bytes32 # 'receipts root' in the yellow paper
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
Expand All @@ -189,7 +189,7 @@ class ExecutionPayload(Container):
class ExecutionPayloadHeader(Container):
# Execution block header fields
parent_hash: Hash32
coinbase: ExecutionAddress
fee_recipient: ExecutionAddress
state_root: Bytes32
receipt_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
Expand All @@ -209,25 +209,25 @@ class ExecutionPayloadHeader(Container):

### Predicates

#### `is_merge_complete`
#### `is_merge_transition_complete`

```python
def is_merge_complete(state: BeaconState) -> bool:
def is_merge_transition_complete(state: BeaconState) -> bool:
return state.latest_execution_payload_header != ExecutionPayloadHeader()
```

#### `is_merge_block`
#### `is_merge_transition_block`

```python
def is_merge_block(state: BeaconState, body: BeaconBlockBody) -> bool:
return not is_merge_complete(state) and body.execution_payload != ExecutionPayload()
def is_merge_transition_block(state: BeaconState, body: BeaconBlockBody) -> bool:
return not is_merge_transition_complete(state) and body.execution_payload != ExecutionPayload()
```

#### `is_execution_enabled`

```python
def is_execution_enabled(state: BeaconState, body: BeaconBlockBody) -> bool:
return is_merge_block(state, body) or is_merge_complete(state)
return is_merge_transition_block(state, body) or is_merge_transition_complete(state)
```

### Misc
Expand Down Expand Up @@ -346,7 +346,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
```python
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
# Verify consistency of the parent hash with respect to the previous execution payload header
if is_merge_complete(state):
if is_merge_transition_complete(state):
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
# Verify random
assert payload.random == get_randao_mix(state, get_current_epoch(state))
Expand All @@ -357,7 +357,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
# Cache execution payload header
state.latest_execution_payload_header = ExecutionPayloadHeader(
parent_hash=payload.parent_hash,
coinbase=payload.coinbase,
fee_recipient=payload.fee_recipient,
state_root=payload.state_root,
receipt_root=payload.receipt_root,
logs_bloom=payload.logs_bloom,
Expand Down Expand Up @@ -406,7 +406,7 @@ Modifications include:
Else, the Merge starts from genesis and the transition is incomplete.

```python
def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
eth1_timestamp: uint64,
deposits: Sequence[Deposit],
execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader()
Expand Down
25 changes: 9 additions & 16 deletions specs/merge/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Used to signal to initiate the payload build process via `notify_forkchoice_upda
class PayloadAttributes(object):
timestamp: uint64
random: Bytes32
fee_recipient: ExecutionAddress
suggested_fee_recipient: ExecutionAddress
```

### `PowBlock`
Expand All @@ -87,7 +87,6 @@ class PowBlock(Container):
block_hash: Hash32
parent_hash: Hash32
total_difficulty: uint256
difficulty: uint256
```

### `get_pow_block`
Expand Down Expand Up @@ -168,14 +167,20 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
state_transition(state, signed_block, True)

# [New in Merge]
if is_merge_block(pre_state, block.body):
if is_merge_transition_block(pre_state, block.body):
validate_merge_block(block)

# Add new block to the store
store.blocks[hash_tree_root(block)] = block
# Add new state for this block to the store
store.block_states[hash_tree_root(block)] = state

# Add proposer score boost if the block is timely
time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
if get_current_slot(store) == block.slot and is_before_attesting_interval:
store.proposer_boost_root = hash_tree_root(block)

# Update justified checkpoint
if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
if state.current_justified_checkpoint.epoch > store.best_justified_checkpoint.epoch:
Expand All @@ -186,17 +191,5 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
# Update finalized checkpoint
if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
store.finalized_checkpoint = state.finalized_checkpoint

# Potentially update justified if different from store
if store.justified_checkpoint != state.current_justified_checkpoint:
# Update justified if new justified is later than store justified
if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
store.justified_checkpoint = state.current_justified_checkpoint
return

# Update justified if store justified is not in chain with finalized checkpoint
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
store.justified_checkpoint = state.current_justified_checkpoint
store.justified_checkpoint = state.current_justified_checkpoint
```
26 changes: 15 additions & 11 deletions specs/merge/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@ Please see related Beacon Chain doc before continuing and use them as a referenc
```python
def get_pow_block_at_terminal_total_difficulty(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
# `pow_chain` abstractly represents all blocks in the PoW chain
for block in pow_chain:
parent = pow_chain[block.parent_hash]
for block in pow_chain.values():
block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
if block_reached_ttd and not parent_reached_ttd:
return block
if block_reached_ttd:
# If genesis block, no parent exists so reaching TTD alone qualifies as valid terminal block
if block.parent_hash == Hash32():
return block
parent = pow_chain[block.parent_hash]
parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
if not parent_reached_ttd:
return block

return None
```
Expand Down Expand Up @@ -106,22 +110,22 @@ 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, fee_recipient, execution_engine)`, where:
1. Set `payload_id = prepare_execution_payload(state, pow_chain, finalized_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
* `finalized_block_hash` is the hash of the latest finalized execution payload (`Hash32()` if none yet finalized)
* `fee_recipient` is the value suggested to be used for the `coinbase` field of the execution payload
* `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],
finalized_block_hash: Hash32,
fee_recipient: ExecutionAddress,
suggested_fee_recipient: ExecutionAddress,
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
if not is_merge_complete(state):
if not is_merge_transition_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
is_activation_epoch_reached = get_current_epoch(state) >= 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 @@ -140,7 +144,7 @@ def prepare_execution_payload(state: BeaconState,
payload_attributes = PayloadAttributes(
timestamp=compute_timestamp_at_slot(state, state.slot),
random=get_randao_mix(state, get_current_epoch(state)),
fee_recipient=fee_recipient,
suggested_fee_recipient=suggested_fee_recipient,
)
return execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
```
Expand Down
3 changes: 1 addition & 2 deletions specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ We define the following Python custom types for type hinting and readability:
| `BLSPubkey` | `Bytes48` | a BLS12-381 public key |
| `BLSSignature` | `Bytes96` | a BLS12-381 signature |


## Constants

The following values are (non-configurable) constants used throughout the specification.
Expand Down Expand Up @@ -1175,7 +1174,7 @@ Before the Ethereum beacon chain genesis has been triggered, and for every Ether
Proof-of-work blocks must only be considered once they are at least `SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE` seconds old (i.e. `eth1_timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time`). Due to this constraint, if `GENESIS_DELAY < SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE`, then the `genesis_time` can happen before the time/state is first known. Values should be configured to avoid this case.

```python
def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
eth1_timestamp: uint64,
deposits: Sequence[Deposit]) -> BeaconState:
fork = Fork(
Expand Down
Loading

0 comments on commit c81c27e

Please sign in to comment.