From af262bec07bbcf25303704b7650ab9da85f1ff69 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 3 Oct 2021 15:12:59 +0300 Subject: [PATCH 1/4] make initialize_beacon_state_from_eth1 work for pre-transition merge --- specs/merge/beacon-chain.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 16f3278ac..275d29a0a 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -354,13 +354,18 @@ 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. ```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) -> BeaconState: fork = Fork( previous_version=MERGE_FORK_VERSION, # [Modified in Merge] for testing only current_version=MERGE_FORK_VERSION, # [Modified in Merge] @@ -397,12 +402,8 @@ 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 + state.latest_execution_payload_header = execution_payload_header return state ``` From 789eea0060285c5b771cb2cca7f046c69afa2d36 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 3 Oct 2021 16:16:59 +0300 Subject: [PATCH 2/4] fix tests. add new generator --- specs/merge/beacon-chain.md | 4 +- .../test/merge/genesis/test_initialization.py | 129 ++++++++++++++++++ tests/formats/genesis/initialization.md | 7 +- 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 275d29a0a..29718b0ec 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -365,7 +365,8 @@ Modifications include: def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, eth1_timestamp: uint64, deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader) -> BeaconState: + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() + ) -> BeaconState: fork = Fork( previous_version=MERGE_FORK_VERSION, # [Modified in Merge] for testing only current_version=MERGE_FORK_VERSION, # [Modified in Merge] @@ -403,6 +404,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, state.next_sync_committee = get_next_sync_committee(state) # [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/test/merge/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py new file mode 100644 index 000000000..853d635c7 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py @@ -0,0 +1,129 @@ +from eth2spec.test.context import ( + single_phase, + spec_test, + with_presets, + with_merge_and_later, +) +from eth2spec.test.helpers.constants import MINIMAL +from eth2spec.test.helpers.deposits import ( + prepare_full_genesis_deposits, +) + + +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_merge_and_later +@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 + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + assert not spec.is_merge_comp(state) + + # yield 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 *without* an execution_payload_header + state = spec.initialize_beacon_state_from_eth1( + eth1_block_hash, + eth1_timestamp, + deposits, + spec.ExecutionPayloadHeader() + ) + + assert not spec.is_merge_complete(state) + + yield 'execution_payload_header', spec.ExecutionPayloadHeader() + + # yield state + 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 + genesis_execution_payload_header = 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=b'\x55' * 32, + block_number=0, + gas_limit=30000000, + base_fee_per_gas=b'\x10' * 32, + block_hash=b'\x99' * 32, + transactions_root=spec.Root(b'\x56' * 32), + + ) + state = spec.initialize_beacon_state_from_eth1( + eth1_block_hash, + eth1_timestamp, + deposits, + genesis_execution_payload_header, + ) + + yield 'execution_payload_header', genesis_execution_payload_header + + assert spec.is_merge_complete(state) + + # yield state + yield 'state', state diff --git a/tests/formats/genesis/initialization.md b/tests/formats/genesis/initialization.md index 73630de51..e7edec173 100644 --- a/tests/formats/genesis/initialization.md +++ b/tests/formats/genesis/initialization.md @@ -26,11 +26,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`: From e235aa82961e0143fa840c72b176cfa03162c71b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 3 Oct 2021 22:20:53 +0800 Subject: [PATCH 3/4] Clean up. Add `execution_payload_header` to initialization `meta.yaml` --- specs/merge/beacon-chain.md | 6 +++--- .../eth2spec/test/merge/genesis/__init__.py | 0 .../test/merge/genesis/test_initialization.py | 21 +++++++++++-------- tests/formats/genesis/initialization.md | 5 +++-- tests/generators/genesis/main.py | 7 ++++++- 5 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/merge/genesis/__init__.py diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 29718b0ec..3e2fd9753 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -355,11 +355,11 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Merge testing only. Modifications include: -1. Use `MERGE_FORK_VERSION` as the current fork version -2. Utilize the Merge `BeaconBlockBody` when constructing the initial `latest_block_header` +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. + Else, the Merge starts from genesis and the transition is incomplete. ```python def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, 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 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py index 853d635c7..384bf57c4 100644 --- a/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py @@ -1,7 +1,9 @@ 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 @@ -17,7 +19,7 @@ def eth1_init_data(eth1_block_hash, eth1_timestamp): } -@with_merge_and_later +@with_phases([MERGE]) @spec_test @single_phase @with_presets([MINIMAL], reason="too slow") @@ -37,11 +39,11 @@ def test_initialize_pre_transition_no_param(spec): 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_comp(state) + assert not spec.is_merge_complete(state) - # yield state yield 'state', state @@ -64,19 +66,20 @@ def test_initialize_pre_transition_empty_payload(spec): yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits - # initialize beacon_state *without* an execution_payload_header + # 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, - spec.ExecutionPayloadHeader() + execution_payload_header=execution_payload_header, ) assert not spec.is_merge_complete(state) - yield 'execution_payload_header', spec.ExecutionPayloadHeader() + yield 'execution_payload_header', execution_payload_header - # yield state yield 'state', state @@ -100,6 +103,7 @@ def test_initialize_post_transition(spec): yield 'deposits', deposits # initialize beacon_state *with* an execution_payload_header + yield 'execution_payload_header', 'meta', True genesis_execution_payload_header = spec.ExecutionPayloadHeader( parent_hash=b'\x30' * 32, coinbase=b'\x42' * 20, @@ -118,12 +122,11 @@ def test_initialize_post_transition(spec): eth1_block_hash, eth1_timestamp, deposits, - genesis_execution_payload_header, + execution_payload_header=genesis_execution_payload_header, ) yield 'execution_payload_header', genesis_execution_payload_header assert spec.is_merge_complete(state) - # yield state yield 'state', state diff --git a/tests/formats/genesis/initialization.md b/tests/formats/genesis/initialization.md index e7edec173..d0d453e5b 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` diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 1f36afd4b..a595db612 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -9,7 +9,12 @@ if __name__ == "__main__": ]} 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, From f1f082fbe7d74aea726a02c0c5f9613a5de58ebc Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 4 Oct 2021 00:30:01 +0800 Subject: [PATCH 4/4] Remove the unused stub constants --- specs/merge/beacon-chain.md | 10 ------- .../pyspec/eth2spec/test/helpers/genesis.py | 27 ++++++++++++++++--- .../test/merge/genesis/test_initialization.py | 18 +++---------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 3e2fd9753..b3d184855 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 | diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 0e9af4cff..cd96c8168 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/test_initialization.py b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py index 384bf57c4..78462263b 100644 --- a/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/merge/genesis/test_initialization.py @@ -10,6 +10,9 @@ 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): @@ -104,20 +107,7 @@ def test_initialize_post_transition(spec): # initialize beacon_state *with* an execution_payload_header yield 'execution_payload_header', 'meta', True - genesis_execution_payload_header = 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=b'\x55' * 32, - block_number=0, - gas_limit=30000000, - base_fee_per_gas=b'\x10' * 32, - block_hash=b'\x99' * 32, - transactions_root=spec.Root(b'\x56' * 32), - - ) + genesis_execution_payload_header = get_sample_genesis_execution_payload_header(spec) state = spec.initialize_beacon_state_from_eth1( eth1_block_hash, eth1_timestamp,