Skip to content

Commit feab65d

Browse files
committed
Add get_attestation_participants
1 parent e7743f5 commit feab65d

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

eth/beacon/helpers.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
Hash32,
1919
)
2020

21+
from eth.utils.bitfield import (
22+
get_bitfield_length,
23+
has_voted,
24+
)
2125
from eth.utils.numeric import (
2226
clamp,
2327
)
@@ -399,3 +403,53 @@ def get_beacon_proposer_index(state: 'BeaconState',
399403
)
400404

401405
return first_shard_committee.committee[slot % len(first_shard_committee.committee)]
406+
407+
408+
#
409+
# Bitfields
410+
#
411+
@to_tuple
412+
def _get_shard_committees(shard_committees: Sequence[ShardCommittee],
413+
shard: int) -> Iterable[ShardCommittee]:
414+
for item in shard_committees:
415+
if item.shard == shard:
416+
yield item
417+
418+
419+
@to_tuple
420+
def get_attestation_participants(state: 'BeaconState',
421+
slot: int,
422+
shard: int,
423+
participation_bitfield: bytes,
424+
epoch_length: int) -> Iterable[int]:
425+
"""
426+
Return the participant indices at for the ``slot`` of shard ``shard``
427+
from ``participation_bitfield``.
428+
"""
429+
# Find the relevant committee
430+
shard_committees = _get_shard_committees(
431+
shard_committees=get_shard_committees_at_slot(
432+
state,
433+
slot,
434+
epoch_length,
435+
),
436+
shard=shard,
437+
)
438+
try:
439+
shard_committee = shard_committees[0]
440+
except IndexError:
441+
raise ValueError("shard_committees should not be empty.")
442+
443+
if len(participation_bitfield) != get_bitfield_length(len(shard_committee.committee)):
444+
raise ValueError(
445+
'Invalid bitfield length,'
446+
"\texpected: %s, found: %s" % (
447+
get_bitfield_length(len(shard_committee.committee)),
448+
len(participation_bitfield),
449+
)
450+
)
451+
452+
# Find the participating attesters in the committee
453+
for bitfield_index, validator_index in enumerate(shard_committee.committee):
454+
if has_voted(participation_bitfield, bitfield_index):
455+
yield validator_index

tests/beacon/test_helpers.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from eth.beacon.helpers import (
1212
_get_element_from_recent_list,
1313
get_active_validator_indices,
14+
get_attestation_participants,
1415
get_attestation_indices,
1516
get_beacon_proposer_index,
1617
get_block_hash,
@@ -579,3 +580,90 @@ def test_get_active_validator_indices(sample_validator_record_params):
579580
)
580581
active_validator_indices = get_active_validator_indices(validators)
581582
assert len(active_validator_indices) == 2
583+
584+
585+
@pytest.mark.parametrize(
586+
(
587+
'num_validators,'
588+
'epoch_length,'
589+
'committee,'
590+
'participation_bitfield,'
591+
'expected'
592+
),
593+
[
594+
(
595+
100,
596+
64,
597+
(10, 11, 12),
598+
b'\00',
599+
(),
600+
),
601+
(
602+
100,
603+
64,
604+
(10, 11, 12),
605+
b'\x80',
606+
(10,),
607+
),
608+
(
609+
100,
610+
64,
611+
(10, 11, 12),
612+
b'\xc0',
613+
(10, 11),
614+
),
615+
(
616+
100,
617+
64,
618+
(10, 11, 12),
619+
b'\x00\x00',
620+
ValueError(),
621+
),
622+
]
623+
)
624+
def test_get_attestation_participants(
625+
monkeypatch,
626+
num_validators,
627+
epoch_length,
628+
committee,
629+
participation_bitfield,
630+
expected,
631+
sample_state):
632+
from eth.beacon import helpers
633+
634+
def mock_get_shard_committees_at_slot(state,
635+
slot,
636+
epoch_length):
637+
return (
638+
ShardCommittee(
639+
shard=0,
640+
committee=committee,
641+
total_validator_count=num_validators,
642+
),
643+
)
644+
645+
monkeypatch.setattr(
646+
helpers,
647+
'get_shard_committees_at_slot',
648+
mock_get_shard_committees_at_slot
649+
)
650+
651+
if isinstance(expected, Exception):
652+
with pytest.raises(ValueError):
653+
get_attestation_participants(
654+
state=sample_state,
655+
slot=0,
656+
shard=0,
657+
participation_bitfield=participation_bitfield,
658+
epoch_length=epoch_length,
659+
)
660+
else:
661+
result = get_attestation_participants(
662+
state=sample_state,
663+
slot=0,
664+
shard=0,
665+
participation_bitfield=participation_bitfield,
666+
epoch_length=epoch_length,
667+
)
668+
669+
assert result == expected

0 commit comments

Comments
 (0)