diff --git a/eth2/beacon/state_machines/forks/serenity/block_processing.py b/eth2/beacon/state_machines/forks/serenity/block_processing.py new file mode 100644 index 0000000000..e4960db7cb --- /dev/null +++ b/eth2/beacon/state_machines/forks/serenity/block_processing.py @@ -0,0 +1,39 @@ +from eth_utils.toolz import ( + first, +) + +from eth2._utils.tuple import update_tuple_item + +from eth2.beacon.types.states import BeaconState +from eth2.beacon.types.blocks import BaseBeaconBlock +from eth2.beacon.types.eth1_data_vote import Eth1DataVote + +from eth2.beacon.state_machines.configs import BeaconConfig + + +def process_eth1_data(state: BeaconState, + block: BaseBeaconBlock, + config: BeaconConfig) -> BeaconState: + try: + vote_index, original_vote = first( + (index, eth1_data_vote) + for index, eth1_data_vote in enumerate(state.eth1_data_votes) + if block.eth1_data == eth1_data_vote.eth1_data + ) + except StopIteration: + new_vote = Eth1DataVote( + eth1_data=block.eth1_data, + vote_count=1, + ) + state = state.copy( + eth1_data_votes=state.eth1_data_votes + (new_vote,) + ) + else: + updated_vote = original_vote.copy( + vote_count=original_vote.vote_count + 1 + ) + state = state.copy( + eth1_data_votes=update_tuple_item(state.eth1_data_votes, vote_index, updated_vote) + ) + + return state diff --git a/tests/eth2/beacon/state_machines/forks/test_serenity_block_processing.py b/tests/eth2/beacon/state_machines/forks/test_serenity_block_processing.py new file mode 100644 index 0000000000..8c680f5bae --- /dev/null +++ b/tests/eth2/beacon/state_machines/forks/test_serenity_block_processing.py @@ -0,0 +1,44 @@ +import pytest + +from eth2.beacon.types.eth1_data_vote import Eth1DataVote +from eth2.beacon.types.states import BeaconState +from eth2.beacon.types.blocks import BeaconBlock + +from eth2.beacon.state_machines.forks.serenity.block_processing import ( + process_eth1_data, +) + +HASH1 = b"\x11" * 32 +HASH2 = b"\x22" * 32 + + +@pytest.mark.parametrize(("original_votes", "block_data", "expected_votes"), ( + ((), HASH1, ((HASH1, 1),)), + (((HASH1, 5),), HASH1, ((HASH1, 6),)), + (((HASH2, 5),), HASH1, ((HASH2, 5), (HASH1, 1))), + (((HASH1, 10), (HASH2, 2)), HASH2, ((HASH1, 10), (HASH2, 3))), +)) +def test_process_eth1_data(original_votes, + block_data, + expected_votes, + sample_beacon_state_params, + sample_beacon_block_params, + config): + eth1_data_votes = tuple( + Eth1DataVote(data, vote_count) + for data, vote_count in original_votes + ) + state = BeaconState(**sample_beacon_state_params).copy( + eth1_data_votes=eth1_data_votes, + ) + + block = BeaconBlock(**sample_beacon_block_params).copy( + eth1_data=block_data, + ) + + updated_state = process_eth1_data(state, block, config) + updated_votes = tuple( + (vote.eth1_data, vote.vote_count) + for vote in updated_state.eth1_data_votes + ) + assert updated_votes == expected_votes