diff --git a/eth2/beacon/committee_helpers.py b/eth2/beacon/committee_helpers.py index 6874233f6c..149773e643 100644 --- a/eth2/beacon/committee_helpers.py +++ b/eth2/beacon/committee_helpers.py @@ -184,26 +184,26 @@ def get_crosslink_committees_at_slot( genesis_epoch=genesis_epoch, ) - if epoch == previous_epoch: - committees_per_epoch = get_previous_epoch_committee_count( + if epoch == current_epoch: + committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=shard_count, slots_per_epoch=slots_per_epoch, target_committee_size=target_committee_size, ) - seed = state.previous_shuffling_seed - shuffling_epoch = state.previous_shuffling_epoch - shuffling_start_shard = state.previous_shuffling_start_shard - elif epoch == current_epoch: - committees_per_epoch = get_current_epoch_committee_count( + seed = state.current_shuffling_seed + shuffling_epoch = state.current_shuffling_epoch + shuffling_start_shard = state.current_shuffling_start_shard + elif epoch == previous_epoch: + committees_per_epoch = get_previous_epoch_committee_count( state=state, shard_count=shard_count, slots_per_epoch=slots_per_epoch, target_committee_size=target_committee_size, ) - seed = state.current_shuffling_seed - shuffling_epoch = state.current_shuffling_epoch - shuffling_start_shard = state.current_shuffling_start_shard + seed = state.previous_shuffling_seed + shuffling_epoch = state.previous_shuffling_epoch + shuffling_start_shard = state.previous_shuffling_start_shard elif epoch == next_epoch: current_committees_per_epoch = get_current_epoch_committee_count( state=state, diff --git a/eth2/beacon/state_machines/forks/serenity/block_validation.py b/eth2/beacon/state_machines/forks/serenity/block_validation.py index 6cd18fc51b..9e62c965e2 100644 --- a/eth2/beacon/state_machines/forks/serenity/block_validation.py +++ b/eth2/beacon/state_machines/forks/serenity/block_validation.py @@ -320,7 +320,7 @@ def validate_attestation_justified_epoch(attestation_data: AttestationData, Validate ``justified_epoch`` field of ``attestation_data``. Raise ``ValidationError`` if it's invalid. """ - if attestation_data.slot >= get_epoch_start_slot(current_epoch, slots_per_epoch): + if slot_to_epoch(attestation_data.slot + 1, slots_per_epoch) >= current_epoch: if attestation_data.justified_epoch != justified_epoch: raise ValidationError( "Attestation ``slot`` is after recent epoch transition but attestation" diff --git a/eth2/beacon/tools/builder/validator.py b/eth2/beacon/tools/builder/validator.py index ba9ab135d3..bcab62e84e 100644 --- a/eth2/beacon/tools/builder/validator.py +++ b/eth2/beacon/tools/builder/validator.py @@ -299,18 +299,44 @@ def create_mock_signed_attestations_at_slot( state: BeaconState, config: BeaconConfig, attestation_slot: Slot, + beacon_block_root: Hash32, keymap: Dict[BLSPubkey, int], voted_attesters_ratio: float=1.0) -> Iterable[Attestation]: """ Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``. """ + slots_per_epoch = config.SLOTS_PER_EPOCH + crosslink_committees_at_slot = get_crosslink_committees_at_slot( + # To avoid the epoch boundary cases state.copy( slot=state.slot + 1, ), attestation_slot, CommitteeConfig(config), ) + + # Get `epoch_boundary_root` + epoch_start_slot = get_epoch_start_slot( + slot_to_epoch(state.slot, slots_per_epoch), + slots_per_epoch, + ) + if epoch_start_slot == state.slot: + epoch_boundary_root = beacon_block_root + else: + epoch_boundary_root = get_block_root( + state, + epoch_start_slot, + config.LATEST_BLOCK_ROOTS_LENGTH, + ) + + # Get `justified_block_root` + justified_block_root = get_block_root( + state, + get_epoch_start_slot(state.justified_epoch, slots_per_epoch), + config.LATEST_BLOCK_ROOTS_LENGTH, + ) + for crosslink_committee in crosslink_committees_at_slot: committee, shard = crosslink_committee @@ -320,16 +346,12 @@ def create_mock_signed_attestations_at_slot( attestation_data = AttestationData( slot=attestation_slot, shard=shard, - beacon_block_root=ZERO_HASH32, - epoch_boundary_root=ZERO_HASH32, + beacon_block_root=beacon_block_root, + epoch_boundary_root=epoch_boundary_root, shard_block_root=ZERO_HASH32, latest_crosslink_root=latest_crosslink_root, - justified_epoch=state.previous_justified_epoch, - justified_block_root=get_block_root( - state, - get_epoch_start_slot(state.previous_justified_epoch, config.SLOTS_PER_EPOCH), - config.LATEST_BLOCK_ROOTS_LENGTH, - ), + justified_epoch=state.justified_epoch, + justified_block_root=justified_block_root, ) yield create_mock_signed_attestation( diff --git a/eth2/beacon/types/states.py b/eth2/beacon/types/states.py index 2d08054e8e..75b8309998 100644 --- a/eth2/beacon/types/states.py +++ b/eth2/beacon/types/states.py @@ -295,11 +295,7 @@ def current_epoch(self, slots_per_epoch: int) -> Epoch: return slot_to_epoch(self.slot, slots_per_epoch) def previous_epoch(self, slots_per_epoch: int, genesis_epoch: int) -> Epoch: - current_epoch: Epoch = self.current_epoch(slots_per_epoch) - if current_epoch == genesis_epoch: - return current_epoch - else: - return Epoch(current_epoch - 1) + return Epoch(max(self.current_epoch(slots_per_epoch) - 1, genesis_epoch)) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1) diff --git a/tests/eth2/beacon/conftest.py b/tests/eth2/beacon/conftest.py index 364de53d03..bd3db42566 100644 --- a/tests/eth2/beacon/conftest.py +++ b/tests/eth2/beacon/conftest.py @@ -8,7 +8,6 @@ ) import eth2._utils.bls as bls -from eth2.beacon._utils.hash import hash_eth2 from eth2.beacon.configs import ( BeaconConfig, CommitteeConfig, @@ -54,7 +53,13 @@ @pytest.fixture(scope="session") def privkeys(): - return [int.from_bytes(hash_eth2(str(i).encode('utf-8'))[:4], 'big') for i in range(100)] + """ + Rationales: + 1. Making the privkeys be small integers to make multiplying easier for tests. + 2. Using ``2**i`` instead of ``i``: + If using ``i``, the combinations of privkeys would not lead to unique pubkeys. + """ + return [2 ** i for i in range(100)] @pytest.fixture(scope="session") diff --git a/tests/eth2/beacon/state_machines/forks/test_serenity_block_attestation_validation.py b/tests/eth2/beacon/state_machines/forks/test_serenity_block_attestation_validation.py index 7ad86003f2..0d2b5a3d21 100644 --- a/tests/eth2/beacon/state_machines/forks/test_serenity_block_attestation_validation.py +++ b/tests/eth2/beacon/state_machines/forks/test_serenity_block_attestation_validation.py @@ -90,13 +90,12 @@ def test_validate_attestation_slot(sample_attestation_data_params, 'is_valid,' ), [ - (13, 1, 2, 0, 1, 5, True), - (13, 0, 2, 0, 1, 5, False), # targeting previous_justified_epoch, should be targeting justified_epoch # noqa: E501 - (13, 4, 2, 0, 1, 5, False), # targeting future epoch, should be targeting justified_epoch - (29, 1, 3, 1, 2, 10, True), - (29, 2, 3, 1, 2, 10, False), # targeting justified_epoch, should be targeting previous_justified_epoch # noqa: E501 - (29, 3, 3, 1, 2, 10, False), # targeting future epoch, should be targeting previous_justified_epoch # noqa: E501 - (10, 1, 1, 1, 1, 10, True), + # slot_to_epoch(attestation_data.slot + 1, slots_per_epoch) >= current_epoch + (23, 2, 3, 1, 2, 8, True), # attestation_data.justified_epoch == justified_epoch + (23, 1, 3, 1, 2, 8, False), # attestation_data.justified_epoch != justified_epoch + # slot_to_epoch(attestation_data.slot + 1, slots_per_epoch) < current_epoch + (22, 1, 3, 1, 2, 8, True), # attestation_data.justified_epoch == previous_justified_epoch + (22, 2, 3, 1, 2, 8, False), # attestation_data.justified_epoch != previous_justified_epoch ] ) def test_validate_attestation_justified_epoch( diff --git a/tests/eth2/beacon/state_machines/forks/test_serenity_operation_processing.py b/tests/eth2/beacon/state_machines/forks/test_serenity_operation_processing.py index 633d3dbb48..7e3310cf5e 100644 --- a/tests/eth2/beacon/state_machines/forks/test_serenity_operation_processing.py +++ b/tests/eth2/beacon/state_machines/forks/test_serenity_operation_processing.py @@ -21,6 +21,7 @@ def test_process_max_attestations(genesis_state, + genesis_block, sample_beacon_block_params, sample_beacon_block_body_params, config, @@ -32,11 +33,12 @@ def test_process_max_attestations(genesis_state, ) attestations = create_mock_signed_attestations_at_slot( - state, - config, - attestation_slot, - keymap, - 1.0, + state=state, + config=config, + attestation_slot=attestation_slot, + beacon_block_root=genesis_block.root, + keymap=keymap, + voted_attesters_ratio=1.0, ) attestations_count = len(attestations) @@ -140,6 +142,7 @@ def test_process_proposer_slashings(genesis_state, ] ) def test_process_attestations(genesis_state, + genesis_block, sample_beacon_block_params, sample_beacon_block_body_params, config, @@ -153,11 +156,12 @@ def test_process_attestations(genesis_state, ) attestations = create_mock_signed_attestations_at_slot( - state, - config, - attestation_slot, - keymap, - 1.0, + state=state, + config=config, + attestation_slot=attestation_slot, + beacon_block_root=genesis_block.root, + keymap=keymap, + voted_attesters_ratio=1.0, ) assert len(attestations) > 0 diff --git a/tests/eth2/beacon/state_machines/test_demo.py b/tests/eth2/beacon/state_machines/test_demo.py index 197947f43b..3dfaa0fb65 100644 --- a/tests/eth2/beacon/state_machines/test_demo.py +++ b/tests/eth2/beacon/state_machines/test_demo.py @@ -24,7 +24,7 @@ 'shard_count' ), [ - (20, 4, 2, 2, 2) + (40, 8, 2, 3, 2) ] ) def test_demo(base_db, @@ -49,12 +49,17 @@ def test_demo(base_db, state = genesis_state block = genesis_block - current_slot = 1 chain_length = 3 * config.SLOTS_PER_EPOCH - attestations = () blocks = (block,) - for current_slot in range(chain_length): - # two epochs + + attestations_map = {} # Dict[Slot, Sequence[Attestation]] + + for current_slot in range(1, chain_length): + if current_slot > config.MIN_ATTESTATION_INCLUSION_DELAY: + attestations = attestations_map[current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY] + else: + attestations = () + block = create_mock_block( state=state, config=config, @@ -85,17 +90,22 @@ def test_demo(base_db, chaindb.persist_block(block, SerenityBeaconBlock) blocks += (block,) - if current_slot > config.MIN_ATTESTATION_INCLUSION_DELAY: - attestation_slot = current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY - attestations = create_mock_signed_attestations_at_slot( - state, - config, - attestation_slot, - keymap, - 1.0, - ) - else: - attestations = () + + # Mock attestations + attestation_slot = current_slot + attestations = create_mock_signed_attestations_at_slot( + state=state, + config=config, + attestation_slot=attestation_slot, + beacon_block_root=block.root, + keymap=keymap, + voted_attesters_ratio=1.0, + ) + attestations_map[attestation_slot] = attestations assert state.slot == chain_length - 1 assert isinstance(sm.block, SerenityBeaconBlock) + + # Justification assertions + assert state.justified_epoch == 2 + assert state.finalized_epoch == 1 diff --git a/tests/eth2/beacon/test_committee_helpers.py b/tests/eth2/beacon/test_committee_helpers.py index 32cf5fca75..6aa474b049 100644 --- a/tests/eth2/beacon/test_committee_helpers.py +++ b/tests/eth2/beacon/test_committee_helpers.py @@ -386,10 +386,10 @@ def mock_generate_seed(state, previous_epoch = state.previous_epoch(slots_per_epoch, genesis_epoch) next_epoch = current_epoch + 1 - if epoch == previous_epoch: - seed = state.previous_shuffling_seed - elif epoch == current_epoch: + if epoch == current_epoch: seed = state.current_shuffling_seed + elif epoch == previous_epoch: + seed = state.previous_shuffling_seed elif epoch == next_epoch: if registry_change or should_reseed: seed = new_seed