Skip to content

Commit 7e3b313

Browse files
authored
Merge pull request #1563 from hwwhww/helpers_4
Rework helper functions - part 2
2 parents be5cb8c + f084ad9 commit 7e3b313

File tree

5 files changed

+557
-283
lines changed

5 files changed

+557
-283
lines changed

Diff for: eth/beacon/block_committees_info.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
'BlockCommitteesInfo',
1313
(
1414
('proposer_index', int),
15-
('proposer_index_in_committee', int),
16-
('proposer_shard_id', int),
15+
('proposer_shard', int),
1716
('proposer_committee_size', int),
1817
('shards_committees', Tuple['ShardCommittee'])
1918
)

Diff for: eth/beacon/helpers.py

+150-119
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
from itertools import (
2-
repeat,
3-
)
4-
51
from typing import (
62
Any,
73
Iterable,
@@ -11,13 +7,22 @@
117
)
128

139
from eth_utils import (
10+
denoms,
1411
to_tuple,
12+
ValidationError,
1513
)
1614

1715
from eth_typing import (
1816
Hash32,
1917
)
2018

19+
from eth.utils.bitfield import (
20+
get_bitfield_length,
21+
has_voted,
22+
)
23+
from eth.utils.blake import (
24+
blake,
25+
)
2126
from eth.utils.numeric import (
2227
clamp,
2328
)
@@ -36,10 +41,8 @@
3641

3742

3843
if TYPE_CHECKING:
39-
from eth.beacon.types.active_states import ActiveState # noqa: F401
4044
from eth.beacon.types.attestation_records import AttestationRecord # noqa: F401
4145
from eth.beacon.types.blocks import BaseBeaconBlock # noqa: F401
42-
from eth.beacon.types.crystallized_states import CrystallizedState # noqa: F401
4346
from eth.beacon.types.states import BeaconState # noqa: F401
4447
from eth.beacon.types.validator_records import ValidatorRecord # noqa: F401
4548

@@ -74,150 +77,80 @@ def _get_element_from_recent_list(
7477
# Get block hash(es)
7578
#
7679
def get_block_hash(
77-
recent_block_hashes: Sequence[Hash32],
78-
current_block_slot_number: int,
79-
slot: int,
80-
epoch_length: int) -> Hash32:
80+
latest_block_hashes: Sequence[Hash32],
81+
current_slot: int,
82+
slot: int) -> Hash32:
8183
"""
82-
Return the blockhash from ``ActiveState.recent_block_hashes`` by
83-
``current_block_slot_number``.
84+
Returns the block hash at a recent ``slot``.
8485
"""
85-
if len(recent_block_hashes) != epoch_length * 2:
86-
raise ValueError(
87-
"Length of recent_block_hashes != epoch_length * 2"
88-
"\texpected: %s, found: %s" % (
89-
epoch_length * 2, len(recent_block_hashes)
90-
)
91-
)
92-
93-
slot_relative_position = current_block_slot_number - epoch_length * 2
86+
slot_relative_position = current_slot - len(latest_block_hashes)
9487
return _get_element_from_recent_list(
95-
recent_block_hashes,
88+
latest_block_hashes,
9689
slot,
9790
slot_relative_position,
9891
)
9992

10093

10194
@to_tuple
102-
def get_hashes_from_recent_block_hashes(
103-
recent_block_hashes: Sequence[Hash32],
104-
current_block_slot_number: int,
95+
def get_hashes_from_latest_block_hashes(
96+
latest_block_hashes: Sequence[Hash32],
97+
current_slot: int,
10598
from_slot: int,
106-
to_slot: int,
107-
epoch_length: int) -> Iterable[Hash32]:
99+
to_slot: int) -> Iterable[Hash32]:
108100
"""
109101
Returns the block hashes between ``from_slot`` and ``to_slot``.
110102
"""
111103
for slot in range(from_slot, to_slot + 1):
112104
yield get_block_hash(
113-
recent_block_hashes,
114-
current_block_slot_number,
105+
latest_block_hashes,
106+
current_slot,
115107
slot,
116-
epoch_length,
117108
)
118109

119110

120-
@to_tuple
121-
def get_hashes_to_sign(recent_block_hashes: Sequence[Hash32],
122-
block: 'BaseBeaconBlock',
123-
epoch_length: int) -> Iterable[Hash32]:
124-
"""
125-
Given the head block to attest to, collect the list of hashes to be
126-
signed in the attestation.
127-
"""
128-
yield from get_hashes_from_recent_block_hashes(
129-
recent_block_hashes,
130-
block.slot_number,
131-
from_slot=block.slot_number - epoch_length + 1,
132-
to_slot=block.slot_number - 1,
133-
epoch_length=epoch_length,
134-
)
135-
yield block.hash
136-
137-
138-
@to_tuple
139-
def get_signed_parent_hashes(recent_block_hashes: Sequence[Hash32],
140-
block: 'BaseBeaconBlock',
141-
attestation: 'AttestationRecord',
142-
epoch_length: int) -> Iterable[Hash32]:
143-
"""
144-
Given an attestation and the block they were included in,
145-
the list of hashes that were included in the signature.
146-
"""
147-
yield from get_hashes_from_recent_block_hashes(
148-
recent_block_hashes,
149-
block.slot_number,
150-
from_slot=attestation.slot - epoch_length + 1,
151-
to_slot=attestation.slot - len(attestation.oblique_parent_hashes),
152-
epoch_length=epoch_length,
153-
)
154-
yield from attestation.oblique_parent_hashes
155-
156-
157-
@to_tuple
158-
def get_new_recent_block_hashes(old_block_hashes: Sequence[Hash32],
159-
parent_slot: int,
160-
current_slot: int,
161-
parent_hash: Hash32) -> Iterable[Hash32]:
162-
163-
shift_size = current_slot - parent_slot
164-
parent_hash_repeat = min(shift_size, len(old_block_hashes))
165-
yield from old_block_hashes[shift_size:]
166-
yield from repeat(parent_hash, parent_hash_repeat)
167-
168-
169111
#
170112
# Get shards_committees or indices
171113
#
172114
@to_tuple
173-
def get_shards_committees_for_slot(
174-
crystallized_state: 'CrystallizedState',
115+
def _get_shard_committees_at_slot(
116+
latest_state_recalculation_slot: int,
117+
shard_committees_at_slots: Sequence[Sequence[ShardCommittee]],
175118
slot: int,
176119
epoch_length: int) -> Iterable[ShardCommittee]:
177-
"""
178-
FIXME
179-
"""
180-
if len(crystallized_state.shard_committee_for_slots) != epoch_length * 2:
120+
if len(shard_committees_at_slots) != epoch_length * 2:
181121
raise ValueError(
182-
"Length of shard_committee_for_slots != epoch_length * 2"
122+
"Length of shard_committees_at_slots != epoch_length * 2"
183123
"\texpected: %s, found: %s" % (
184-
epoch_length * 2, len(crystallized_state.shard_committee_for_slots)
124+
epoch_length * 2, len(shard_committees_at_slots)
185125
)
186126
)
187127

188-
slot_relative_position = crystallized_state.last_state_recalc - epoch_length
128+
slot_relative_position = latest_state_recalculation_slot - epoch_length
189129

190130
yield from _get_element_from_recent_list(
191-
crystallized_state.shard_committee_for_slots,
131+
shard_committees_at_slots,
192132
slot,
193133
slot_relative_position,
194134
)
195135

196136

197-
@to_tuple
198-
def get_attestation_indices(crystallized_state: 'CrystallizedState',
199-
attestation: 'AttestationRecord',
200-
epoch_length: int) -> Iterable[int]:
137+
def get_shard_committees_at_slot(state: 'BeaconState',
138+
slot: int,
139+
epoch_length: int) -> Tuple[ShardCommittee]:
201140
"""
202-
FIXME
203-
Return committee of the given attestation.
141+
Return the ``ShardCommittee`` for the ``slot``.
204142
"""
205-
shard_id = attestation.shard_id
206-
207-
shards_committees_for_slot = get_shards_committees_for_slot(
208-
crystallized_state,
209-
attestation.slot,
210-
epoch_length,
143+
return _get_shard_committees_at_slot(
144+
latest_state_recalculation_slot=state.latest_state_recalculation_slot,
145+
shard_committees_at_slots=state.shard_committees_at_slots,
146+
slot=slot,
147+
epoch_length=epoch_length,
211148
)
212149

213-
for shard_committee in shards_committees_for_slot:
214-
if shard_committee.shard_id == shard_id:
215-
yield from shard_committee.committee
216-
217150

218151
def get_active_validator_indices(validators: Sequence['ValidatorRecord']) -> Tuple[int, ...]:
219152
"""
220-
Gets indices of active validators from ``validators``.
153+
Get indices of active validators from ``validators``.
221154
"""
222155
return tuple(
223156
i for i, v in enumerate(validators)
@@ -235,7 +168,7 @@ def _get_shards_committees_for_shard_indices(
235168
total_validator_count: int,
236169
shard_count: int) -> Iterable[ShardCommittee]:
237170
"""
238-
Returns filled [ShardCommittee] tuple.
171+
Return filled [ShardCommittee] tuple.
239172
"""
240173
for index, indices in enumerate(shard_indices):
241174
yield ShardCommittee(
@@ -320,45 +253,143 @@ def get_new_shuffling(*,
320253

321254

322255
#
323-
# Get proposer postition
256+
# Get proposer position
324257
#
325258
def get_block_committees_info(parent_block: 'BaseBeaconBlock',
326-
crystallized_state: 'CrystallizedState',
259+
state: 'BeaconState',
327260
epoch_length: int) -> BlockCommitteesInfo:
328-
shards_committees = get_shards_committees_for_slot(
329-
crystallized_state,
330-
parent_block.slot_number,
261+
shards_committees = get_shard_committees_at_slot(
262+
state,
263+
parent_block.slot,
331264
epoch_length,
332265
)
333266
"""
334-
FIXME
335267
Return the block committees and proposer info with BlockCommitteesInfo pack.
336268
"""
337269
# `proposer_index_in_committee` th attester in `shard_committee`
338270
# is the proposer of the parent block.
339271
try:
340272
shard_committee = shards_committees[0]
341273
except IndexError:
342-
raise ValueError("shards_committees should not be empty.")
274+
raise ValidationError("shards_committees should not be empty.")
343275

344276
proposer_committee_size = len(shard_committee.committee)
345277
if proposer_committee_size <= 0:
346-
raise ValueError(
278+
raise ValidationError(
347279
"The first committee should not be empty"
348280
)
349281

350282
proposer_index_in_committee = (
351-
parent_block.slot_number %
283+
parent_block.slot %
352284
proposer_committee_size
353285
)
354286

355-
# The index in CrystallizedState.validators
356287
proposer_index = shard_committee.committee[proposer_index_in_committee]
357288

358289
return BlockCommitteesInfo(
359290
proposer_index=proposer_index,
360-
proposer_index_in_committee=proposer_index_in_committee,
361-
proposer_shard_id=shard_committee.shard_id,
291+
proposer_shard=shard_committee.shard,
362292
proposer_committee_size=proposer_committee_size,
363293
shards_committees=shards_committees,
364294
)
295+
296+
297+
def get_beacon_proposer_index(state: 'BeaconState',
298+
slot: int,
299+
epoch_length: int) -> int:
300+
"""
301+
Return the beacon proposer index for the ``slot``.
302+
"""
303+
shard_committees = get_shard_committees_at_slot(
304+
state,
305+
slot,
306+
epoch_length,
307+
)
308+
try:
309+
first_shard_committee = shard_committees[0]
310+
except IndexError:
311+
raise ValidationError("shard_committees should not be empty.")
312+
313+
proposer_committee_size = len(first_shard_committee.committee)
314+
315+
if proposer_committee_size <= 0:
316+
raise ValidationError(
317+
"The first committee should not be empty"
318+
)
319+
320+
return first_shard_committee.committee[slot % len(first_shard_committee.committee)]
321+
322+
323+
#
324+
# Bitfields
325+
#
326+
@to_tuple
327+
def get_attestation_participants(state: 'BeaconState',
328+
slot: int,
329+
shard: int,
330+
participation_bitfield: bytes,
331+
epoch_length: int) -> Iterable[int]:
332+
"""
333+
Return the participants' indices at the ``slot`` of shard ``shard``
334+
from ``participation_bitfield``.
335+
"""
336+
# Find the relevant committee
337+
# Filter by slot
338+
shard_committees_at_slot = get_shard_committees_at_slot(
339+
state,
340+
slot,
341+
epoch_length,
342+
)
343+
# Filter by shard
344+
shard_committees = tuple(
345+
[
346+
shard_committee
347+
for shard_committee in shard_committees_at_slot
348+
if shard_committee.shard == shard
349+
]
350+
)
351+
352+
try:
353+
shard_committee = shard_committees[0]
354+
except IndexError:
355+
raise ValidationError("shard_committees should not be empty.")
356+
357+
if len(participation_bitfield) != get_bitfield_length(len(shard_committee.committee)):
358+
raise ValidationError(
359+
'Invalid bitfield length,'
360+
"\texpected: %s, found: %s" % (
361+
get_bitfield_length(len(shard_committee.committee)),
362+
len(participation_bitfield),
363+
)
364+
)
365+
366+
# Find the participating attesters in the committee
367+
for bitfield_index, validator_index in enumerate(shard_committee.committee):
368+
if has_voted(participation_bitfield, bitfield_index):
369+
yield validator_index
370+
371+
372+
#
373+
# Misc
374+
#
375+
def get_effective_balance(validator: 'ValidatorRecord', max_deposit: int) -> int:
376+
"""
377+
Return the effective balance (also known as "balance at stake") for the ``validator``.
378+
"""
379+
return min(validator.balance, max_deposit * denoms.gwei)
380+
381+
382+
def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_chain_tip: Hash32,
383+
index: int,
384+
pubkey: int,
385+
flag: int) -> Hash32:
386+
"""
387+
Compute the next hash in the validator registry delta hash chain.
388+
"""
389+
return blake(
390+
current_validator_registry_delta_chain_tip +
391+
flag.to_bytes(1, 'big') +
392+
index.to_bytes(3, 'big') +
393+
# TODO: currently, we use 256-bit pubkey which is different form the spec
394+
pubkey.to_bytes(32, 'big')
395+
)

0 commit comments

Comments
 (0)