Skip to content

Commit 874986b

Browse files
committed
PR feedback
1 parent 9885c68 commit 874986b

File tree

12 files changed

+514
-378
lines changed

12 files changed

+514
-378
lines changed

eth/beacon/block_committees_info.py

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,20 @@
11
from typing import (
22
Iterable,
3+
NamedTuple,
34
TYPE_CHECKING,
45
)
56

67
if TYPE_CHECKING:
78
from eth.beacon.types.shard_and_committees import ShardAndCommittee # noqa: F401
89

910

10-
class BlockCommitteesInfo:
11-
_proposer_index = None # validator index
12-
_proposer_index_in_committee = None
13-
_proposer_shard_id = None
14-
_proposer_committee_size = None
15-
_shards_and_committees = None
16-
17-
def __init__(self,
18-
proposer_index: int,
19-
proposer_index_in_committee: int,
20-
proposer_shard_id: int,
21-
proposer_committee_size: int,
22-
shards_and_committees: Iterable['ShardAndCommittee']) -> None:
23-
self._proposer_index = proposer_index
24-
self._proposer_index_in_committee = proposer_index_in_committee
25-
self._proposer_shard_id = proposer_shard_id
26-
self._proposer_committee_size = proposer_committee_size
27-
self._shards_and_committees = shards_and_committees
28-
29-
@property
30-
def proposer_index(self) -> int:
31-
return self._proposer_index
32-
33-
@property
34-
def proposer_index_in_committee(self) -> int:
35-
return self._proposer_index_in_committee
36-
37-
@property
38-
def proposer_shard_id(self) -> int:
39-
return self._proposer_shard_id
40-
41-
@property
42-
def proposer_committee_size(self) -> int:
43-
return self._proposer_committee_size
44-
45-
@property
46-
def shards_and_committees(self) -> Iterable['ShardAndCommittee']:
47-
return self._shards_and_committees
11+
BlockCommitteesInfo = NamedTuple(
12+
'BlockCommitteesInfo',
13+
(
14+
('proposer_index', int),
15+
('proposer_index_in_committee', int),
16+
('proposer_shard_id', int),
17+
('proposer_committee_size', int),
18+
('shards_and_committees', Iterable['ShardAndCommittee'])
19+
)
20+
)

eth/beacon/db/chain.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def get_canonical_block_hash(self, slot: int) -> Hash32:
7272
def get_canonical_block_by_slot(self, slot: int) -> BaseBeaconBlock:
7373
pass
7474

75+
@abstractmethod
76+
def get_canonical_block_hash_by_slot(self, slot: int) -> Hash32:
77+
pass
78+
7579
@abstractmethod
7680
def get_canonical_head(self) -> BaseBeaconBlock:
7781
pass
@@ -195,7 +199,7 @@ def _get_canonical_block_hash(db: BaseDB, slot: int) -> Hash32:
195199

196200
def get_canonical_block_by_slot(self, slot: int) -> BaseBeaconBlock:
197201
"""
198-
Return the block header with the given slot in the canonical chain.
202+
Return the block with the given slot in the canonical chain.
199203
200204
Raise BlockNotFound if there's no block with the given slot in the
201205
canonical chain.
@@ -207,10 +211,26 @@ def _get_canonical_block_by_slot(
207211
cls,
208212
db: BaseDB,
209213
slot: int) -> BaseBeaconBlock:
210-
validate_slot(slot)
211-
canonical_block_hash = cls._get_canonical_block_hash(db, slot)
214+
canonical_block_hash = cls._get_canonical_block_hash_by_slot(db, slot)
212215
return cls._get_block_by_hash(db, canonical_block_hash)
213216

217+
def get_canonical_block_hash_by_slot(self, slot: int) -> Hash32:
218+
"""
219+
Return the block hash with the given slot in the canonical chain.
220+
221+
Raise BlockNotFound if there's no block with the given slot in the
222+
canonical chain.
223+
"""
224+
return self._get_canonical_block_hash_by_slot(self.db, slot)
225+
226+
@classmethod
227+
def _get_canonical_block_hash_by_slot(
228+
cls,
229+
db: BaseDB,
230+
slot: int) -> Hash32:
231+
validate_slot(slot)
232+
return cls._get_canonical_block_hash(db, slot)
233+
214234
def get_canonical_head(self) -> BaseBeaconBlock:
215235
"""
216236
Return the current block at the head of the chain.

eth/beacon/helpers.py

Lines changed: 106 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import functools
12
from itertools import (
23
repeat,
34
)
5+
6+
from cytoolz import (
7+
pipe
8+
)
49
from typing import (
510
Any,
611
Iterable,
@@ -17,6 +22,15 @@
1722
Hash32,
1823
)
1924

25+
from eth.utils import bls
26+
from eth.utils.bitfield import (
27+
set_voted,
28+
)
29+
from eth.utils.blake import blake
30+
from eth.utils.numeric import (
31+
clamp,
32+
)
33+
2034
from eth.beacon.block_committees_info import BlockCommitteesInfo
2135
from eth.beacon.types.shard_and_committees import (
2236
ShardAndCommittee,
@@ -220,18 +234,6 @@ def get_active_validator_indices(dynasty: int,
220234
#
221235
# Shuffling
222236
#
223-
def clamp(minval: int, x: int, maxval: int) -> int:
224-
"""
225-
Bound the given ``x`` between ``minval`` and ``maxval``
226-
"""
227-
if x <= minval:
228-
return minval
229-
elif x >= maxval:
230-
return maxval
231-
else:
232-
return x
233-
234-
235237
def _get_shuffling_committee_slot_portions(
236238
active_validators_size: int,
237239
cycle_length: int,
@@ -333,8 +335,8 @@ def get_new_shuffling(*,
333335
active_validators_size = len(active_validators)
334336
committees_per_slot = clamp(
335337
1,
338+
shard_count // cycle_length,
336339
active_validators_size // cycle_length // (min_committee_size * 2) + 1,
337-
shard_count // cycle_length
338340
)
339341
shuffled_active_validator_indices = shuffle(active_validators, seed)
340342

@@ -365,12 +367,13 @@ def get_block_committees_info(parent_block: 'BaseBeaconBlock',
365367
"""
366368
Returns the proposer index in committee and the ``shard_id``.
367369
"""
368-
if len(shards_and_committees) <= 0:
369-
raise ValueError("shards_and_committees should not be empty.")
370-
371370
# `proposer_index_in_committee` th attester in `shard_and_committee`
372371
# is the proposer of the parent block.
373-
shard_and_committee = shards_and_committees[0]
372+
try:
373+
shard_and_committee = shards_and_committees[0]
374+
except IndexError:
375+
raise ValueError("shards_and_committees should not be empty.")
376+
374377
proposer_committee_size = len(shard_and_committee.committee)
375378
if proposer_committee_size <= 0:
376379
raise ValueError(
@@ -392,3 +395,89 @@ def get_block_committees_info(parent_block: 'BaseBeaconBlock',
392395
proposer_committee_size=proposer_committee_size,
393396
shards_and_committees=shards_and_committees,
394397
)
398+
399+
400+
#
401+
# Signatures and Aggregation
402+
#
403+
def create_signing_message(slot: int,
404+
parent_hashes: Iterable[Hash32],
405+
shard_id: int,
406+
shard_block_hash: Hash32,
407+
justified_slot: int) -> bytes:
408+
# TODO: will be updated to hashed encoded attestation
409+
return blake(
410+
slot.to_bytes(8, byteorder='big') +
411+
b''.join(parent_hashes) +
412+
shard_id.to_bytes(2, byteorder='big') +
413+
shard_block_hash +
414+
justified_slot.to_bytes(8, 'big')
415+
)
416+
417+
418+
def aggregate_attestation_record(last_justified_slot: int,
419+
recent_block_hashes: Iterable[Hash32],
420+
block: 'BaseBeaconBlock',
421+
votes: Iterable[Tuple[int, bytes, int]],
422+
proposer_attestation: 'AttestationRecord',
423+
cycle_length: int) -> 'AttestationRecord':
424+
"""
425+
Aggregate the votes.
426+
427+
TODO: Write tests
428+
"""
429+
# Get signing message
430+
parent_hashes = get_hashes_to_sign(
431+
recent_block_hashes,
432+
block,
433+
cycle_length,
434+
)
435+
message = create_signing_message(
436+
block.slot_number,
437+
parent_hashes,
438+
proposer_attestation.shard_id,
439+
block.shard_block_hash,
440+
last_justified_slot,
441+
)
442+
443+
bitfield, sigs = aggregate_votes(
444+
message,
445+
votes,
446+
proposer_attestation.bitfield,
447+
proposer_attestation.sigs,
448+
)
449+
450+
return proposer_attestation.copy(
451+
bitfield=bitfield,
452+
sigs=bls.aggregate_sigs(sigs),
453+
)
454+
455+
456+
def aggregate_votes(message: bytes,
457+
votes: Iterable[Tuple[int, bytes, int]],
458+
pre_bitfield: bytes,
459+
pre_sigs: Iterable[bytes]) -> Tuple[bytes, Iterable[int]]:
460+
# Update the bitfield and append the signatures
461+
sigs_with_committe_info = tuple(
462+
(sig, committee_index)
463+
for (committee_index, sig, public_key)
464+
in votes
465+
if bls.verify(message, public_key, sig)
466+
)
467+
try:
468+
sigs, committee_indices = zip(*sigs_with_committe_info)
469+
except ValueError:
470+
sigs = ()
471+
committee_indices = ()
472+
473+
sigs = sigs + tuple(pre_sigs)
474+
bitfield = pre_bitfield
475+
bitfield = pipe(
476+
bitfield,
477+
*(
478+
functools.partial(set_voted, index=committee_index)
479+
for committee_index in committee_indices
480+
)
481+
)
482+
483+
return bitfield, bls.aggregate_sigs(sigs)

0 commit comments

Comments
 (0)