diff --git a/README.md b/README.md index 9e5d7dc428..1ae37766f4 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The merge is still actively in development. The exact specification has not been * [Fork Choice changes](specs/merge/fork-choice.md) * [Validator additions](specs/merge/validator.md) * [Client settings](specs/merge/client-settings.md) + * [P2P Networking](specs/merge/p2p-interface.md) ### Sharding diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index dbd3e63683..b22f89a4db 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -689,7 +689,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, eth1_timestamp: uint64, deposits: Sequence[Deposit]) -> BeaconState: fork = Fork( - previous_version=GENESIS_FORK_VERSION, + previous_version=ALTAIR_FORK_VERSION, # [Modified in Altair] for testing only current_version=ALTAIR_FORK_VERSION, # [Modified in Altair] epoch=GENESIS_EPOCH, ) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 56476cedd1..b3d1848552 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -13,7 +13,6 @@ - [Constants](#constants) - [Execution](#execution) - [Configuration](#configuration) - - [Genesis testing settings](#genesis-testing-settings) - [Transition settings](#transition-settings) - [Containers](#containers) - [Extended containers](#extended-containers) @@ -71,15 +70,6 @@ This patch adds transaction execution to the beacon chain as part of the Merge f ## Configuration -### Genesis testing settings - -*Note*: These configuration settings do not apply to the mainnet and are utilized only by pure Merge testing. - -| Name | Value | -| - | - | -| `GENESIS_GAS_LIMIT` | `uint64(30000000)` (= 30,000,000) | -| `GENESIS_BASE_FEE_PER_GAS` | `Bytes32('0x00ca9a3b00000000000000000000000000000000000000000000000000000000')` (= 1,000,000,000) | - ### Transition settings | Name | Value | @@ -257,7 +247,7 @@ The Engine API may be used to implement them with an external execution engine. ```python def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: """ - Returns ``True`` iff ``execution_payload`` is valid with respect to ``self.execution_state``. + Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. """ ... ``` @@ -354,15 +344,21 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe ## Testing *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Merge testing only. - -*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) initialize `latest_execution_payload_header`. +Modifications include: +1. Use `MERGE_FORK_VERSION` as the current fork version. +2. Utilize the Merge `BeaconBlockBody` when constructing the initial `latest_block_header`. +3. Initialize `latest_execution_payload_header`. + If `execution_payload_header == ExecutionPayloadHeader()`, then the Merge has not yet occurred. + Else, the Merge starts from genesis and the transition is incomplete. ```python def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, eth1_timestamp: uint64, - deposits: Sequence[Deposit]) -> BeaconState: + deposits: Sequence[Deposit], + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() + ) -> BeaconState: fork = Fork( - previous_version=GENESIS_FORK_VERSION, + previous_version=MERGE_FORK_VERSION, # [Modified in Merge] for testing only current_version=MERGE_FORK_VERSION, # [Modified in Merge] epoch=GENESIS_EPOCH, ) @@ -397,12 +393,9 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, state.current_sync_committee = get_next_sync_committee(state) state.next_sync_committee = get_next_sync_committee(state) - # [New in Merge] Initialize the execution payload header (with block number set to 0) - state.latest_execution_payload_header.block_hash = eth1_block_hash - state.latest_execution_payload_header.timestamp = eth1_timestamp - state.latest_execution_payload_header.random = eth1_block_hash - state.latest_execution_payload_header.gas_limit = GENESIS_GAS_LIMIT - state.latest_execution_payload_header.base_fee_per_gas = GENESIS_BASE_FEE_PER_GAS + # [New in Merge] Initialize the execution payload header + # If empty, will initialize a chain that has not yet gone through the Merge transition + state.latest_execution_payload_header = execution_payload_header return state ``` diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index 9084fa2f71..524cb55242 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.1.0 +1.1.1 diff --git a/tests/core/pyspec/eth2spec/test/altair/merkle/test_single_proof.py b/tests/core/pyspec/eth2spec/test/altair/merkle/test_single_proof.py index f9aa68adda..31cdd13bb1 100644 --- a/tests/core/pyspec/eth2spec/test/altair/merkle/test_single_proof.py +++ b/tests/core/pyspec/eth2spec/test/altair/merkle/test_single_proof.py @@ -1,12 +1,11 @@ from eth2spec.test.context import ( spec_state_test, - with_phases, + with_altair_and_later, ) -from eth2spec.test.helpers.constants import ALTAIR from eth2spec.test.helpers.merkle import build_proof -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test def test_next_sync_committee_merkle_proof(spec, state): yield "state", state @@ -25,7 +24,7 @@ def test_next_sync_committee_merkle_proof(spec, state): ) -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test def test_finality_root_merkle_proof(spec, state): yield "state", state diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/networking/test_networking.py b/tests/core/pyspec/eth2spec/test/altair/unittests/networking/test_networking.py index 37d50611dc..6d9dca5237 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/networking/test_networking.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/networking/test_networking.py @@ -1,6 +1,6 @@ from eth2spec.test.context import ( - with_altair_and_later, spec_state_test, + with_altair_and_later, ) from eth2spec.test.helpers.state import ( transition_to, diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py index 4443f97e0b..91be0a0a61 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py @@ -1,11 +1,10 @@ from eth2spec.test.context import ( spec_state_test, - with_phases, + with_altair_and_later, ) -from eth2spec.test.helpers.constants import ALTAIR -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test def test_weight_denominator(spec, state): assert ( @@ -17,7 +16,7 @@ def test_weight_denominator(spec, state): ) == spec.WEIGHT_DENOMINATOR -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test def test_inactivity_score(spec, state): assert spec.config.INACTIVITY_SCORE_BIAS <= spec.config.INACTIVITY_SCORE_RECOVERY_RATE diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py index c69957de53..15444df819 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py @@ -1,17 +1,14 @@ from eth2spec.test.context import ( spec_state_test, with_presets, - with_phases, + with_altair_and_later, ) from eth2spec.test.helpers.attestations import next_epoch_with_attestations from eth2spec.test.helpers.block import ( build_empty_block, build_empty_block_for_next_slot, ) -from eth2spec.test.helpers.constants import ( - ALTAIR, - MINIMAL, -) +from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.state import ( next_slots, state_transition_and_sign_block, @@ -22,7 +19,7 @@ from eth2spec.test.helpers.merkle import build_proof -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test def test_process_light_client_update_not_updated(spec, state): pre_snapshot = spec.LightClientSnapshot( @@ -81,7 +78,7 @@ def test_process_light_client_update_not_updated(spec, state): assert store.snapshot == pre_snapshot -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_timeout(spec, state): @@ -147,7 +144,7 @@ def test_process_light_client_update_timeout(spec, state): assert store.snapshot.header == update.header -@with_phases([ALTAIR]) +@with_altair_and_later @spec_state_test @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_finality_updated(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index ef92efaded..6062648d60 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -463,8 +463,8 @@ def is_post_merge(spec): return spec.fork not in FORKS_BEFORE_MERGE -with_altair_and_later = with_phases([ALTAIR, MERGE]) -with_merge_and_later = with_phases([MERGE]) # TODO: include sharding when spec stabilizes. +with_altair_and_later = with_all_phases_except([PHASE0]) +with_merge_and_later = with_all_phases_except([PHASE0, ALTAIR]) def only_generator(reason): diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 0d03447a76..59308e102a 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -3,7 +3,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None): Assuming a pre-state of the same slot, build a valid ExecutionPayload without any transactions. """ latest = state.latest_execution_payload_header - timestamp = spec.compute_time_at_slot(state, state.slot) + timestamp = spec.compute_timestamp_at_slot(state, state.slot) empty_txs = spec.List[spec.Transaction, spec.MAX_TRANSACTIONS_PER_PAYLOAD]() if randao_mix is None: diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 0e9af4cff9..cd96c8168f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -20,6 +20,25 @@ def build_mock_validator(spec, i: int, balance: int): ) +def get_sample_genesis_execution_payload_header(spec, + eth1_block_hash=None): + if eth1_block_hash is None: + eth1_block_hash = b'\x55' * 32 + return spec.ExecutionPayloadHeader( + parent_hash=b'\x30' * 32, + coinbase=b'\x42' * 20, + state_root=b'\x20' * 32, + receipt_root=b'\x20' * 32, + logs_bloom=b'\x35' * spec.BYTES_PER_LOGS_BLOOM, + random=eth1_block_hash, + block_number=0, + gas_limit=30000000, + base_fee_per_gas=spec.Bytes32('0x00ca9a3b00000000000000000000000000000000000000000000000000000000'), + block_hash=eth1_block_hash, + transactions_root=spec.Root(b'\x56' * 32), + ) + + def create_genesis_state(spec, validator_balances, activation_threshold): deposit_root = b'\x42' * 32 @@ -76,9 +95,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): if spec.fork not in FORKS_BEFORE_MERGE: # Initialize the execution payload header (with block number and genesis time set to 0) - state.latest_execution_payload_header.block_hash = eth1_block_hash - state.latest_execution_payload_header.random = eth1_block_hash - state.latest_execution_payload_header.gas_limit = spec.GENESIS_GAS_LIMIT - state.latest_execution_payload_header.base_fee_per_gas = spec.GENESIS_BASE_FEE_PER_GAS + state.latest_execution_payload_header = get_sample_genesis_execution_payload_header( + spec, + eth1_block_hash=eth1_block_hash, + ) return state diff --git a/tests/core/pyspec/eth2spec/test/merge/genesis/__init__.py b/tests/core/pyspec/eth2spec/test/merge/genesis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py new file mode 100644 index 0000000000..78462263b2 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py @@ -0,0 +1,122 @@ +from eth2spec.test.context import ( + MERGE, + single_phase, + spec_test, + with_presets, + with_phases, + with_merge_and_later, +) +from eth2spec.test.helpers.constants import MINIMAL +from eth2spec.test.helpers.deposits import ( + prepare_full_genesis_deposits, +) +from eth2spec.test.helpers.genesis import ( + get_sample_genesis_execution_payload_header, +) + + +def eth1_init_data(eth1_block_hash, eth1_timestamp): + yield 'eth1', { + 'eth1_block_hash': '0x' + eth1_block_hash.hex(), + 'eth1_timestamp': int(eth1_timestamp), + } + + +@with_phases([MERGE]) +@spec_test +@single_phase +@with_presets([MINIMAL], reason="too slow") +def test_initialize_pre_transition_no_param(spec): + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposits, deposit_root, _ = prepare_full_genesis_deposits( + spec, + spec.MAX_EFFECTIVE_BALANCE, + deposit_count, + signed=True, + ) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.config.MIN_GENESIS_TIME + + yield from eth1_init_data(eth1_block_hash, eth1_timestamp) + yield 'deposits', deposits + + # initialize beacon_state *without* an execution_payload_header + yield 'execution_payload_header', 'meta', False + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + assert not spec.is_merge_complete(state) + + yield 'state', state + + +@with_merge_and_later +@spec_test +@single_phase +@with_presets([MINIMAL], reason="too slow") +def test_initialize_pre_transition_empty_payload(spec): + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposits, deposit_root, _ = prepare_full_genesis_deposits( + spec, + spec.MAX_EFFECTIVE_BALANCE, + deposit_count, + signed=True, + ) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.config.MIN_GENESIS_TIME + + yield from eth1_init_data(eth1_block_hash, eth1_timestamp) + yield 'deposits', deposits + + # initialize beacon_state *with* an *empty* execution_payload_header + yield 'execution_payload_header', 'meta', True + execution_payload_header = spec.ExecutionPayloadHeader() + state = spec.initialize_beacon_state_from_eth1( + eth1_block_hash, + eth1_timestamp, + deposits, + execution_payload_header=execution_payload_header, + ) + + assert not spec.is_merge_complete(state) + + yield 'execution_payload_header', execution_payload_header + + yield 'state', state + + +@with_merge_and_later +@spec_test +@single_phase +@with_presets([MINIMAL], reason="too slow") +def test_initialize_post_transition(spec): + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposits, deposit_root, _ = prepare_full_genesis_deposits( + spec, + spec.MAX_EFFECTIVE_BALANCE, + deposit_count, + signed=True, + ) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.config.MIN_GENESIS_TIME + + yield from eth1_init_data(eth1_block_hash, eth1_timestamp) + yield 'deposits', deposits + + # initialize beacon_state *with* an execution_payload_header + yield 'execution_payload_header', 'meta', True + genesis_execution_payload_header = get_sample_genesis_execution_payload_header(spec) + state = spec.initialize_beacon_state_from_eth1( + eth1_block_hash, + eth1_timestamp, + deposits, + execution_payload_header=genesis_execution_payload_header, + ) + + yield 'execution_payload_header', genesis_execution_payload_header + + assert spec.is_merge_complete(state) + + yield 'state', state diff --git a/tests/formats/genesis/initialization.md b/tests/formats/genesis/initialization.md index 73630de51c..d0d453e5b6 100644 --- a/tests/formats/genesis/initialization.md +++ b/tests/formats/genesis/initialization.md @@ -17,8 +17,9 @@ eth1_timestamp: int -- An integer. The timestamp of the block, in seconds. A yaml file to help read the deposit count: ```yaml -description: string -- Optional. Description of test case, purely for debugging purposes. -deposits_count: int -- Amount of deposits. +description: string -- Optional. Description of test case, purely for debugging purposes. +deposits_count: int -- Amount of deposits. +execution_payload_header: bool -- `execution_payload_header` field is filled or not. If `true`, `execution_payload_header.ssz_snappy` file exists. ``` ### `deposits_.ssz_snappy` @@ -26,11 +27,16 @@ deposits_count: int -- Amount of deposits. A series of files, with `` in range `[0, deposits_count)`. Deposits need to be processed in order. Each file is a SSZ-snappy encoded `Deposit` object. +### `execution_payload_header.ssz_snappy` + +*Note*: Param added only for the Merge and subsequent forks. + +The execution payload header that state is initialized with. An SSZ-snappy encoded `BeaconState` object. + ### `state.ssz_snappy` The expected genesis state. An SSZ-snappy encoded `BeaconState` object. - ## Processing To process this test, build a genesis state with the provided `eth1_block_hash`, `eth1_timestamp` and `deposits`: diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 1f36afd4b9..a595db6120 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -9,7 +9,12 @@ ]} altair_mods = phase_0_mods # we have new unconditional lines in `initialize_beacon_state_from_eth1` and we want to test it - merge_mods = altair_mods + merge_mods = { + **{key: 'eth2spec.test.merge.genesis.test_' + key for key in [ + 'initialization', + ]}, + **altair_mods, + } all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, diff --git a/tests/generators/merkle/main.py b/tests/generators/merkle/main.py index 7203c5f193..44fbec10c6 100644 --- a/tests/generators/merkle/main.py +++ b/tests/generators/merkle/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import ALTAIR +from eth2spec.test.helpers.constants import ALTAIR, MERGE from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators @@ -6,9 +6,11 @@ altair_mods = {key: 'eth2spec.test.altair.merkle.test_' + key for key in [ 'single_proof', ]} + merge_mods = altair_mods all_mods = { - ALTAIR: altair_mods + ALTAIR: altair_mods, + MERGE: merge_mods, } run_state_test_generators(runner_name="merkle", all_mods=all_mods)