Skip to content

Commit 0bf3f85

Browse files
committed
Merge branch 'dev' into JustinDrake-patch-7
2 parents 7140838 + 973a874 commit 0bf3f85

File tree

17 files changed

+497
-56
lines changed

17 files changed

+497
-56
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ while the details are in review and may change.
4343
* [ethereum.org](https://ethereum.org) high-level description of the merge [here](https://ethereum.org/en/eth2/docking/)
4444
* Specifications:
4545
* [Beacon Chain changes](specs/merge/beacon-chain.md)
46+
* [Merge fork](specs/merge/fork.md)
4647
* [Fork Choice changes](specs/merge/fork-choice.md)
4748
* [Validator additions](specs/merge/validator.md)
4849

configs/mainnet.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ SHARDING_FORK_VERSION: 0x03000000
3232
SHARDING_FORK_EPOCH: 18446744073709551615
3333

3434
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
35-
TRANSITION_TOTAL_DIFFICULTY: 4294967296
35+
MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296
3636

3737

3838
# Time parameters

configs/minimal.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ SHARDING_FORK_VERSION: 0x03000001
3131
SHARDING_FORK_EPOCH: 18446744073709551615
3232

3333
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
34-
TRANSITION_TOTAL_DIFFICULTY: 4294967296
34+
MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296
3535

3636

3737
# Time parameters

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ def sundry_functions(cls) -> str:
510510
511511
def get_pow_block(hash: Bytes32) -> PowBlock:
512512
return PowBlock(block_hash=hash, is_valid=True, is_processed=True,
513-
total_difficulty=config.TRANSITION_TOTAL_DIFFICULTY)
513+
total_difficulty=uint256(0), difficulty=uint256(0))
514514
515515
516516
def get_execution_state(execution_state_root: Bytes32) -> ExecutionState:
@@ -871,6 +871,7 @@ def finalize_options(self):
871871
specs/phase0/validator.md
872872
specs/phase0/weak-subjectivity.md
873873
specs/merge/beacon-chain.md
874+
specs/merge/fork.md
874875
specs/merge/fork-choice.md
875876
specs/merge/validator.md
876877
"""

specs/altair/p2p-interface.md

+18
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,23 @@ New topics are added in Altair to support the sync committees and the beacon blo
7474

7575
The specification around the creation, validation, and dissemination of messages has not changed from the Phase 0 document.
7676

77+
The derivation of the `message-id` has changed starting with Altair to incorporate the message `topic` along with the message `data`. These are fields of the `Message` Protobuf, and interpreted as empty byte strings if missing.
78+
The `message-id` MUST be the following 20 byte value computed from the message:
79+
* If `message.data` has a valid snappy decompression, set `message-id` to the first 20 bytes of the `SHA256` hash of
80+
the concatenation of the following data: `MESSAGE_DOMAIN_VALID_SNAPPY`, the length of the topic byte string (encoded as little-endian `uint64`),
81+
the topic byte string, and the snappy decompressed message data:
82+
i.e. `SHA256(MESSAGE_DOMAIN_VALID_SNAPPY + uint_to_bytes(uint64(len(message.topic))) + message.topic + snappy_decompress(message.data))[:20]`.
83+
* Otherwise, set `message-id` to the first 20 bytes of the `SHA256` hash of
84+
the concatenation of the following data: `MESSAGE_DOMAIN_INVALID_SNAPPY`, the length of the topic byte string (encoded as little-endian `uint64`),
85+
the topic byte string, and the raw message data:
86+
i.e. `SHA256(MESSAGE_DOMAIN_INVALID_SNAPPY + uint_to_bytes(uint64(len(message.topic))) + message.topic + message.data)[:20]`.
87+
88+
Implementations may need to carefully handle the function that computes the `message-id`. In particular, messages on topics with the Phase 0
89+
fork digest should use the `message-id` procedure specified in the Phase 0 document.
90+
Messages on topics with the Altair fork digest should use the `message-id` procedure defined here.
91+
If an implementation only supports a single `message-id` function, it can define a switch inline;
92+
for example, `if topic in phase0_topics: return phase0_msg_id_fn(message) else return altair_msg_id_fn(message)`.
93+
7794
The new topics along with the type of the `data` field of a gossipsub message are given in this table:
7895

7996
| Name | Message Type |
@@ -144,6 +161,7 @@ The following validations MUST pass before forwarding the `sync_committee_messag
144161
- _[IGNORE]_ The signature's slot is for the current slot (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance), i.e. `sync_committee_message.slot == current_slot`.
145162
- _[IGNORE]_ The block being signed over (`sync_committee_message.beacon_block_root`) has been seen (via both gossip and non-gossip sources).
146163
- _[IGNORE]_ There has been no other valid sync committee signature for the declared `slot` for the validator referenced by `sync_committee_message.validator_index`.
164+
Note this validation is _per topic_ so that for a given `slot`, multiple messages could be forwarded with the same `validator_index` as long as the `subnet_id`s are distinct.
147165
- _[REJECT]_ The `subnet_id` is valid for the given validator, i.e. `subnet_id in compute_subnets_for_sync_committee(state, sync_committee_message.validator_index)`.
148166
Note this validation implies the validator is part of the broader current sync committee along with the correct subcommittee.
149167
- _[REJECT]_ The `signature` is valid for the message `beacon_block_root` for the validator referenced by `validator_index`.

specs/merge/beacon-chain.md

+63-15
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
- [Custom types](#custom-types)
1515
- [Constants](#constants)
1616
- [Execution](#execution)
17-
- [Configuration](#configuration)
18-
- [Merge](#merge)
1917
- [Containers](#containers)
2018
- [Extended containers](#extended-containers)
2119
- [`BeaconBlockBody`](#beaconblockbody)
@@ -31,11 +29,12 @@
3129
- [Misc](#misc)
3230
- [`compute_timestamp_at_slot`](#compute_timestamp_at_slot)
3331
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
34-
- [Execution engine](#execution-engine)
35-
- [`on_payload`](#on_payload)
32+
- [Execution engine](#execution-engine)
33+
- [`on_payload`](#on_payload)
3634
- [Block processing](#block-processing)
3735
- [Execution payload processing](#execution-payload-processing)
3836
- [`process_execution_payload`](#process_execution_payload)
37+
- [Initialize state for pure Merge testnets and test vectors](#initialize-state-for-pure-merge-testnets-and-test-vectors)
3938

4039
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
4140
<!-- /TOC -->
@@ -63,17 +62,6 @@ This patch adds transaction execution to the beacon chain as part of the merge.
6362
| `MAX_TRANSACTIONS_PER_PAYLOAD` | `uint64(2**14)` (= 16,384) |
6463
| `BYTES_PER_LOGS_BLOOM` | `uint64(2**8)` (= 256) |
6564

66-
## Configuration
67-
68-
### Merge
69-
70-
*Note*: The configuration value `MERGE_FORK_EPOCH` is not final.
71-
72-
| Name | Value |
73-
| - | - |
74-
| `MERGE_FORK_VERSION` | `Version('0x02000000')` |
75-
| `MERGE_FORK_EPOCH` | `Epoch(18446744073709551615)` |
76-
7765
## Containers
7866

7967
### Extended containers
@@ -234,3 +222,63 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
234222
transactions_root=hash_tree_root(payload.transactions),
235223
)
236224
```
225+
226+
## Initialize state for pure Merge testnets and test vectors
227+
228+
This helper function is only for initializing the state for pure Merge testnets and tests.
229+
230+
*Note*: The function `initialize_beacon_state_from_eth1` is modified: (1) using `MERGE_FORK_VERSION` as the current fork version, (2) utilizing the Merge `BeaconBlockBody` when constructing the initial `latest_block_header`, and (3) adding initial `latest_execution_payload_header`.
231+
232+
```python
233+
def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
234+
eth1_timestamp: uint64,
235+
deposits: Sequence[Deposit]) -> BeaconState:
236+
fork = Fork(
237+
previous_version=GENESIS_FORK_VERSION,
238+
current_version=MERGE_FORK_VERSION, # [Modified in Merge]
239+
epoch=GENESIS_EPOCH,
240+
)
241+
state = BeaconState(
242+
genesis_time=eth1_timestamp + GENESIS_DELAY,
243+
fork=fork,
244+
eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
245+
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
246+
randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
247+
)
248+
249+
# Process deposits
250+
leaves = list(map(lambda deposit: deposit.data, deposits))
251+
for index, deposit in enumerate(deposits):
252+
deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
253+
state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
254+
process_deposit(state, deposit)
255+
256+
# Process activations
257+
for index, validator in enumerate(state.validators):
258+
balance = state.balances[index]
259+
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
260+
if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
261+
validator.activation_eligibility_epoch = GENESIS_EPOCH
262+
validator.activation_epoch = GENESIS_EPOCH
263+
264+
# Set genesis validators root for domain separation and chain versioning
265+
state.genesis_validators_root = hash_tree_root(state.validators)
266+
267+
# [New in Merge] Construct execution payload header
268+
# Note: initialized with zero block height
269+
state.latest_execution_payload_header = ExecutionPayloadHeader(
270+
block_hash=eth1_block_hash,
271+
parent_hash=Hash32(),
272+
coinbase=Bytes20(),
273+
state_root=Bytes32(),
274+
number=uint64(0),
275+
gas_limit=uint64(0),
276+
gas_used=uint64(0),
277+
timestamp=eth1_timestamp,
278+
receipt_root=Bytes32(),
279+
logs_bloom=ByteVector[BYTES_PER_LOGS_BLOOM](),
280+
transactions_root=Root(),
281+
)
282+
283+
return state
284+
```

specs/merge/fork-choice.md

+27-19
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
- [`ExecutionEngine`](#executionengine)
1313
- [`set_head`](#set_head)
1414
- [`finalize_block`](#finalize_block)
15-
- [Containers](#containers)
16-
- [`PowBlock`](#powblock)
17-
- [Helper functions](#helper-functions)
18-
- [`get_pow_block`](#get_pow_block)
19-
- [`is_valid_transition_block`](#is_valid_transition_block)
15+
- [Helpers](#helpers)
16+
- [`TransitionStore`](#transitionstore)
17+
- [`PowBlock`](#powblock)
18+
- [`get_pow_block`](#get_pow_block)
19+
- [`is_valid_terminal_pow_block`](#is_valid_terminal_pow_block)
2020
- [Updated fork-choice handlers](#updated-fork-choice-handlers)
21-
- [`on_block`](#on_block)
21+
- [`on_block`](#on_block)
2222

2323
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
2424
<!-- /TOC -->
@@ -66,44 +66,52 @@ def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool:
6666
...
6767
```
6868

69-
## Containers
69+
## Helpers
7070

71-
#### `PowBlock`
71+
### `TransitionStore`
7272

7373
```python
74-
class PowBlock(Container):
74+
@dataclass
75+
class TransitionStore(object):
76+
transition_total_difficulty: uint256
77+
```
78+
79+
### `PowBlock`
80+
81+
```python
82+
@dataclass
83+
class PowBlock(object):
7584
block_hash: Hash32
7685
is_processed: boolean
7786
is_valid: boolean
7887
total_difficulty: uint256
88+
difficulty: uint256
7989
```
8090

81-
## Helper functions
82-
83-
#### `get_pow_block`
91+
### `get_pow_block`
8492

8593
Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given the hash of the PoW block returns its data.
8694

8795
*Note*: The `eth_getBlockByHash` JSON-RPC method does not distinguish invalid blocks from blocks that haven't been processed yet. Either extending this existing method or implementing a new one is required.
8896

89-
#### `is_valid_transition_block`
97+
### `is_valid_terminal_pow_block`
9098

9199
Used by fork-choice handler, `on_block`.
92100

93101
```python
94-
def is_valid_transition_block(block: PowBlock) -> bool:
95-
is_total_difficulty_reached = block.total_difficulty >= TRANSITION_TOTAL_DIFFICULTY
102+
def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlock) -> bool:
103+
is_total_difficulty_reached = block.total_difficulty >= transition_store.transition_total_difficulty
96104
return block.is_valid and is_total_difficulty_reached
97105
```
98106

99107
## Updated fork-choice handlers
100108

101-
#### `on_block`
109+
### `on_block`
102110

103111
*Note*: The only modification is the addition of the verification of transition block conditions.
104112

105113
```python
106-
def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
114+
def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: TransitionStore=None) -> None:
107115
block = signed_block.message
108116
# Parent block must be known
109117
assert block.parent_root in store.block_states
@@ -119,11 +127,11 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
119127
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
120128

121129
# [New in Merge]
122-
if is_transition_block(pre_state, block):
130+
if (transition_store is not None) and is_merge_block(pre_state, block):
123131
# Delay consideration of block until PoW block is processed by the PoW node
124132
pow_block = get_pow_block(block.body.execution_payload.parent_hash)
125133
assert pow_block.is_processed
126-
assert is_valid_transition_block(pow_block)
134+
assert is_valid_terminal_pow_block(transition_store, pow_block)
127135

128136
# Check the block is valid and compute the post-state
129137
state = pre_state.copy()

0 commit comments

Comments
 (0)