From a8160f1634eab48644a44d75ae22edb126d5f654 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 10 Apr 2021 00:53:37 +0800 Subject: [PATCH] Try to initialize state with pure Altair spec in tests --- specs/altair/beacon-chain.md | 47 +++++++++++++++++++ tests/core/pyspec/eth2spec/test/context.py | 14 ++---- .../eth2spec/test/helpers/fork_choice.py | 5 +- .../pyspec/eth2spec/test/helpers/genesis.py | 16 ++++++- 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 9b476bce1..9f9af9de7 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -52,6 +52,7 @@ - [Slashings](#slashings) - [Participation flags updates](#participation-flags-updates) - [Sync committee updates](#sync-committee-updates) +- [Initialize state for testnets](#initialize-state-for-testnets) @@ -661,3 +662,49 @@ def process_sync_committee_updates(state: BeaconState) -> None: state.current_sync_committee = state.next_sync_committee state.next_sync_committee = get_sync_committee(state, next_epoch + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) ``` + +## Initialize state for testnets + +This helper function is only for initialize Altair testnets and tests. + +```python +def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, + eth1_timestamp: uint64, + deposits: Sequence[Deposit]) -> BeaconState: + fork = Fork( + previous_version=GENESIS_FORK_VERSION, + current_version=ALTAIR_FORK_VERSION, + epoch=GENESIS_EPOCH, + ) + state = BeaconState( + genesis_time=eth1_timestamp + GENESIS_DELAY, + fork=fork, + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy + ) + + # Process deposits + leaves = list(map(lambda deposit: deposit.data, deposits)) + for index, deposit in enumerate(deposits): + deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) + state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) + process_deposit(state, deposit) + + # Process activations + for index, validator in enumerate(state.validators): + balance = state.balances[index] + validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + validator.activation_eligibility_epoch = GENESIS_EPOCH + validator.activation_epoch = GENESIS_EPOCH + + # Set genesis validators root for domain separation and chain versioning + state.genesis_validators_root = hash_tree_root(state.validators) + + # Fill in sync committees + state.current_sync_committee = get_sync_committee(state, get_current_epoch(state)) + state.next_sync_committee = get_sync_committee(state, get_current_epoch(state) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + + return state +``` diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 7ae1b9541..34b6e79a1 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -75,17 +75,11 @@ class SpecForks(TypedDict, total=False): def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int], spec: Spec, phases: SpecForks): - - p0 = phases[PHASE0] - balances = balances_fn(p0) - activation_threshold = threshold_fn(p0) - - state = create_genesis_state(spec=p0, validator_balances=balances, + phase = phases[spec.fork] + balances = balances_fn(phase) + activation_threshold = threshold_fn(phase) + state = create_genesis_state(spec=phase, validator_balances=balances, activation_threshold=activation_threshold) - # TODO: upgrade to merge spec, and later sharding. - if spec.fork == ALTAIR: - state = phases[ALTAIR].upgrade_to_altair(state) - return state diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py index 2ca37768b..f3b80b2ac 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py @@ -1,7 +1,5 @@ from eth_utils import encode_hex -from eth2spec.phase0 import spec as phase0_spec - def get_anchor_root(spec, state): anchor_block_header = state.latest_block_header.copy() @@ -58,8 +56,7 @@ def get_genesis_forkchoice_store(spec, genesis_state): def get_genesis_forkchoice_store_and_block(spec, genesis_state): assert genesis_state.slot == spec.GENESIS_SLOT - # The genesis block must be a Phase 0 `BeaconBlock` - genesis_block = phase0_spec.BeaconBlock(state_root=genesis_state.hash_tree_root()) + genesis_block = spec.BeaconBlock(state_root=genesis_state.hash_tree_root()) return spec.get_forkchoice_store(genesis_state, genesis_block), genesis_block diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 14fd9aa47..5f2cd5281 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -20,6 +20,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): deposit_root = b'\x42' * 32 eth1_block_hash = b'\xda' * 32 + current_version = spec.GENESIS_FORK_VERSION + if spec.fork == 'altair': # TODO: fix `context.py` dependency + current_version = spec.ALTAIR_FORK_VERSION state = spec.BeaconState( genesis_time=0, eth1_deposit_index=len(validator_balances), @@ -30,7 +33,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold): ), fork=spec.Fork( previous_version=spec.GENESIS_FORK_VERSION, - current_version=spec.GENESIS_FORK_VERSION, + current_version=current_version, epoch=spec.GENESIS_EPOCH, ), latest_block_header=spec.BeaconBlockHeader(body_root=spec.hash_tree_root(spec.BeaconBlockBody())), @@ -47,8 +50,19 @@ def create_genesis_state(spec, validator_balances, activation_threshold): if validator.effective_balance >= activation_threshold: validator.activation_eligibility_epoch = spec.GENESIS_EPOCH validator.activation_epoch = spec.GENESIS_EPOCH + if spec.fork != 'phase0': # TODO: fix `context.py` dependency + state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.inactivity_scores.append(spec.uint64(0)) # Set genesis validators root for domain separation and chain versioning state.genesis_validators_root = spec.hash_tree_root(state.validators) + if spec.fork != 'phase0': # TODO: fix `context.py` dependency + # Fill in sync committees + state.current_sync_committee = spec.get_sync_committee(state, spec.get_current_epoch(state)) + state.next_sync_committee = ( + spec.get_sync_committee(state, spec.get_current_epoch(state) + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + ) + return state