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
Conversation
There was a problem hiding this 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.
There was a problem hiding this 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.
eth/beacon/helpers.py
Outdated
proposer_committee_size = len(first_shard_committee.committee) | ||
|
||
if proposer_committee_size <= 0: | ||
raise ValueError( |
There was a problem hiding this comment.
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 bytry/except
catching theValueError
)
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
tests/beacon/conftest.py
Outdated
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)]), |
There was a problem hiding this comment.
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))
eth/beacon/helpers.py
Outdated
recent_block_hashes: Sequence[Hash32], | ||
current_block_slot_number: int, | ||
latest_block_hashes: Sequence[Hash32], | ||
current_block_slot: int, |
There was a problem hiding this comment.
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
current_block_slot: int, | |
current_slot: int, |
eth/beacon/helpers.py
Outdated
""" | ||
if len(recent_block_hashes) != epoch_length * 2: | ||
if len(latest_block_hashes) != epoch_length * 2: |
There was a problem hiding this comment.
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.
eth/beacon/helpers.py
Outdated
) | ||
) | ||
|
||
slot_relative_position = current_block_slot_number - epoch_length * 2 | ||
slot_relative_position = current_block_slot - epoch_length * 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use len
slot_relative_position = current_block_slot - epoch_length * 2 | |
slot_relative_position = current_block_slot - len(latest_block_hashes)` |
eth/beacon/helpers.py
Outdated
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], |
There was a problem hiding this comment.
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
eth/beacon/helpers.py
Outdated
|
||
@to_tuple | ||
def get_new_recent_block_hashes(old_block_hashes: Sequence[Hash32], | ||
def get_new_latest_block_hashes(old_block_hashes: Sequence[Hash32], |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
eth/beacon/helpers.py
Outdated
proposer_committee_size = len(first_shard_committee.committee) | ||
|
||
if proposer_committee_size <= 0: | ||
raise ValueError( |
There was a problem hiding this comment.
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 :) ]
eth/beacon/helpers.py
Outdated
try: | ||
shard_committee = shard_committees[0] | ||
except IndexError: | ||
raise ValueError("shard_committees should not be empty.") |
There was a problem hiding this comment.
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.
eth/beacon/helpers.py
Outdated
raise ValueError("shard_committees should not be empty.") | ||
|
||
if len(participation_bitfield) != get_bitfield_length(len(shard_committee.committee)): | ||
raise ValueError( |
There was a problem hiding this comment.
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
tests/beacon/test_helpers.py
Outdated
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): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer needed
Co-Authored-By: hwwhww <hwwang156@gmail.com>
What was wrong?
#1510
How was it fixed?
get_shard_committees_at_slot
_get_shard_committees_at_slot
is for making the tests easier.get_block_hash
get_beacon_proposer_index
get_attestation_participants
get_effective_balance
get_new_validator_registry_delta_chain_tip
Also, make the tests for these functions not depend on genesis state or block.
Cute Animal Picture