Skip to content
This repository has been archived by the owner on Jul 1, 2021. It is now read-only.

Fix attestation, previous epoch logic and builder tools #300

Merged
merged 6 commits into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions eth2/beacon/committee_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
38 changes: 30 additions & 8 deletions eth2/beacon/tools/builder/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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(
Expand Down
6 changes: 1 addition & 5 deletions eth2/beacon/types/states.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
9 changes: 7 additions & 2 deletions tests/eth2/beacon/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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``:
The combinations of validators would not lead to unique pubkeys.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be ...would lead to unique pubkeys?

"""
return [2 ** i for i in range(100)]


@pytest.fixture(scope="session")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -114,6 +113,7 @@ def test_validate_attestation_justified_epoch(
)

if is_valid:
# slot_to_epoch(attestation_data.slot + 1, slots_per_epoch) >= current_epoch
hwwhww marked this conversation as resolved.
Show resolved Hide resolved
validate_attestation_justified_epoch(
attestation_data,
current_epoch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@


def test_process_max_attestations(genesis_state,
genesis_block,
sample_beacon_block_params,
sample_beacon_block_body_params,
config,
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
42 changes: 26 additions & 16 deletions tests/eth2/beacon/state_machines/test_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
'shard_count'
),
[
(20, 4, 2, 2, 2)
(40, 8, 2, 3, 2)
]
)
def test_demo(base_db,
Expand All @@ -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,
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions tests/eth2/beacon/test_committee_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down