Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework helper functions - part 2 #1563

Merged
merged 10 commits into from Dec 13, 2018
Merged

Rework helper functions - part 2 #1563

merged 10 commits into from Dec 13, 2018

Conversation

hwwhww
Copy link
Contributor

@hwwhww hwwhww commented Dec 8, 2018

What was wrong?

#1510

How was it fixed?

  • Fix get_shard_committees_at_slot
    • The reason why I add _get_shard_committees_at_slot is for making the tests easier.
  • Fix get_block_hash
  • Add get_beacon_proposer_index
  • Add get_attestation_participants
  • Add get_effective_balance
  • Add get_new_validator_registry_delta_chain_tip

Also, make the tests for these functions not depend on genesis state or block.

Cute Animal Picture

Copy link
Contributor

@ChihChengLiang ChihChengLiang left a comment

Choose a reason for hiding this comment

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

Nice work!
For other reviewers, note that get_attestation_participants is different from the spec. In spec the function takes attestation_data as argument and extracts slot and shard from it.

eth/beacon/helpers.py Outdated Show resolved Hide resolved
eth/beacon/helpers.py Outdated Show resolved Hide resolved
Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

Only reviews implementation architecture and not correctness WRT specification.

proposer_committee_size = len(first_shard_committee.committee)

if proposer_committee_size <= 0:
raise ValueError(
Copy link
Member

Choose a reason for hiding this comment

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

Do you think ValidationError would be more appropriate for these? My loose guideline has been:

  • ValidationError for things that we might encounter in live network conditions (like someone sending us a transaction with an invalid signature).
  • ValueError for things that indicate broken code (and that when they occur we address them directly rather than by try/except catching the ValueError)

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed.

In extreme conditions in which there are fewer validators than there are slots in an epoch (< 64 validators), some slots would have no associated committee and thus no associated proposer. In this case, an incoming block for such an empty slot should fail validation.

[if we have fewer than 64 validators we probably have bigger problems on our hands, but the code should still run :) ]

current_validator_registry_delta_chain_tip +
flag.to_bytes(1, 'big') +
index.to_bytes(3, 'big') +
# TODO: currently, we use 256-bit pubkey which is different form the spec
Copy link
Member

Choose a reason for hiding this comment

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

Not for this PR but something I think we should address.

We have tended to use eth_keys data types for private and public key representations. I suspect that we'll have to make some modifications to eth_keys to support new key types? If this is accurate, do you think you can open issues both here and in eth_keys to track those needs?

return {
'slot': 10,
'randao_reveal': b'\x55' * 32,
'candidate_pow_receipt_root': b'\x55' * 32,
'ancestor_hashes': (),
'ancestor_hashes': tuple([ZERO_HASH32 for _ in range(2 * epoch_length)]),
Copy link
Member

Choose a reason for hiding this comment

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

Maybe more idiomatic.

ancestor_hashes = tuple(itertools.repeat(ZERO_HASH32, 2 * epoch_length))

recent_block_hashes: Sequence[Hash32],
current_block_slot_number: int,
latest_block_hashes: Sequence[Hash32],
current_block_slot: int,
Copy link
Contributor

Choose a reason for hiding this comment

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

I would just call this current_slot as the state can transition slot by slot without necessarily having a block

Suggested change
current_block_slot: int,
current_slot: int,

"""
if len(recent_block_hashes) != epoch_length * 2:
if len(latest_block_hashes) != epoch_length * 2:
Copy link
Contributor

Choose a reason for hiding this comment

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

This condition is not valid. lastest_block_hashes are added to one by one (as new slots progress), but are then trimmed down an entire EPOCH_LENGTH at the end of the per-epoch processing.

)
)

slot_relative_position = current_block_slot_number - epoch_length * 2
slot_relative_position = current_block_slot - epoch_length * 2
Copy link
Contributor

Choose a reason for hiding this comment

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

use len

Suggested change
slot_relative_position = current_block_slot - epoch_length * 2
slot_relative_position = current_block_slot - len(latest_block_hashes)`

slot,
epoch_length,
)


@to_tuple
def get_hashes_to_sign(recent_block_hashes: Sequence[Hash32],
def get_hashes_to_sign(latest_block_hashes: Sequence[Hash32],
Copy link
Contributor

Choose a reason for hiding this comment

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

We no longer sign the series of hashes. Instead we sign a bunch of discrete data that can be pulled from state.
I believe this can be removed.
See https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#attestationdata


@to_tuple
def get_new_recent_block_hashes(old_block_hashes: Sequence[Hash32],
def get_new_latest_block_hashes(old_block_hashes: Sequence[Hash32],
Copy link
Contributor

Choose a reason for hiding this comment

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

We no longer need this. The latest_block_hashes are now just updated with a one-liner

state.latest_block_hashes = state.latest_block_hashes + [latest_hash]

If we keep the method, we should simplify it to the spec requirements

@@ -170,54 +157,45 @@ def get_new_recent_block_hashes(old_block_hashes: Sequence[Hash32],
# Get shards_committees or indices
#
@to_tuple
def get_shards_committees_for_slot(
crystallized_state: 'CrystallizedState',
def _get_shard_committees_at_slot(
Copy link
Contributor

Choose a reason for hiding this comment

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

get_shard_committees_at_slot has a simplified logic and no longer uses lastest_state_recalculation_slot (this field is actually entirely removed).

The slot_relative_position is now calculated from the current slot in the state, so we should pass that slot in and use it here instead.

https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#get_shard_committees_at_slot

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opened #1575 to address it.

proposer_committee_size = len(first_shard_committee.committee)

if proposer_committee_size <= 0:
raise ValueError(
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed.

In extreme conditions in which there are fewer validators than there are slots in an epoch (< 64 validators), some slots would have no associated committee and thus no associated proposer. In this case, an incoming block for such an empty slot should fail validation.

[if we have fewer than 64 validators we probably have bigger problems on our hands, but the code should still run :) ]

try:
shard_committee = shard_committees[0]
except IndexError:
raise ValueError("shard_committees should not be empty.")
Copy link
Contributor

Choose a reason for hiding this comment

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

Following @pipermerriam's logic, this too should be a ValidationError.

The way a user would trigger it would be to pack a block with an attestation not represented in by a committee at that slot. This should cause block validation to fail.

raise ValueError("shard_committees should not be empty.")

if len(participation_bitfield) != get_bitfield_length(len(shard_committee.committee)):
raise ValueError(
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, a user could trigger this by adding malformed attestations to a block.
Throw ValidationError

from_slot,
to_slot,
epoch_length,
)
assert len(result) == to_slot - from_slot + 1


@pytest.mark.xfail(reason="Need to be fixed")
def test_get_hashes_to_sign(genesis_block, epoch_length):
def test_get_hashes_to_sign(sample_block, epoch_length):
Copy link
Contributor

Choose a reason for hiding this comment

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

No longer needed

@hwwhww hwwhww merged commit 7e3b313 into ethereum:master Dec 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants