Skip to content
This repository was archived by the owner on Jul 1, 2021. It is now read-only.

Commit 0a7e121

Browse files
authored
Merge pull request #633 from NIC619/add_attestation_logic_in_validator_plugin
Add attestation handling to validator and receive server
2 parents e783dba + f31ce3f commit 0a7e121

File tree

9 files changed

+525
-98
lines changed

9 files changed

+525
-98
lines changed

eth2/beacon/tools/builder/validator.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,6 @@ def create_mock_signed_attestations_at_slot(
507507
for crosslink_committee in crosslink_committees_at_slot:
508508
committee, shard = crosslink_committee
509509

510-
num_voted_attesters = int(len(committee) * voted_attesters_ratio)
511510
previous_crosslink = state.latest_crosslinks[shard]
512511

513512
attestation_data = AttestationData(
@@ -533,6 +532,78 @@ def create_mock_signed_attestations_at_slot(
533532
)
534533

535534

535+
def create_signed_attestation_at_slot(
536+
state: BeaconState,
537+
config: Eth2Config,
538+
state_machine: BaseBeaconStateMachine,
539+
attestation_slot: Slot,
540+
beacon_block_root: Hash32,
541+
validator_privkeys: Dict[ValidatorIndex, int],
542+
committee: Tuple[ValidatorIndex, ...],
543+
shard: Shard) -> Attestation:
544+
"""
545+
Create the attestations of the given ``attestation_slot`` slot with ``validator_privkeys``.
546+
"""
547+
state_transition = state_machine.state_transition
548+
state = state_transition.apply_state_transition_without_block(
549+
state,
550+
attestation_slot,
551+
)
552+
553+
# Get `target_root`
554+
target_root = _get_target_root(state, config, beacon_block_root)
555+
556+
previous_crosslink = state.latest_crosslinks[shard]
557+
558+
attestation_data = AttestationData(
559+
slot=attestation_slot,
560+
beacon_block_root=beacon_block_root,
561+
source_epoch=state.current_justified_epoch,
562+
source_root=state.current_justified_root,
563+
target_root=target_root,
564+
shard=shard,
565+
previous_crosslink=previous_crosslink,
566+
crosslink_data_root=ZERO_HASH32,
567+
)
568+
569+
message_hash = AttestationDataAndCustodyBit(
570+
data=attestation_data,
571+
custody_bit=False
572+
).root
573+
574+
signatures = [
575+
sign_transaction(
576+
message_hash=message_hash,
577+
privkey=privkey,
578+
fork=state.fork,
579+
slot=attestation_data.slot,
580+
signature_domain=SignatureDomain.DOMAIN_ATTESTATION,
581+
slots_per_epoch=config.SLOTS_PER_EPOCH,
582+
)
583+
for _, privkey in validator_privkeys.items()
584+
]
585+
586+
voting_committee_indices = [
587+
CommitteeIndex(committee.index(validator_index))
588+
for validator_index in validator_privkeys
589+
]
590+
# aggregate signatures and construct participant bitfield
591+
aggregation_bitfield, aggregate_signature = aggregate_votes(
592+
bitfield=get_empty_bitfield(len(committee)),
593+
sigs=(),
594+
voting_sigs=signatures,
595+
voting_committee_indices=voting_committee_indices,
596+
)
597+
598+
# create attestation from attestation_data, particpipant_bitfield, and signature
599+
return Attestation(
600+
aggregation_bitfield=aggregation_bitfield,
601+
data=attestation_data,
602+
custody_bitfield=Bitfield(get_empty_bitfield(len(aggregation_bitfield))),
603+
aggregate_signature=aggregate_signature,
604+
)
605+
606+
536607
#
537608
# VoluntaryExit
538609
#

tests/core/p2p-proto/bcc/test_commands.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ async def test_send_no_attestations(request, event_loop):
148148

149149
message = await msg_buffer.msg_queue.get()
150150
assert isinstance(message.command, Attestations)
151-
assert message.payload == ()
151+
assert message.payload == {
152+
"encoded_attestations": (),
153+
}
152154

153155

154156
@pytest.mark.asyncio
@@ -174,7 +176,7 @@ async def test_send_single_attestation(request, event_loop):
174176

175177
message = await msg_buffer.msg_queue.get()
176178
assert isinstance(message.command, Attestations)
177-
assert message.payload == (ssz.encode(attestation),)
179+
assert message.payload["encoded_attestations"] == (ssz.encode(attestation),)
178180

179181

180182
@pytest.mark.asyncio
@@ -202,4 +204,5 @@ async def test_send_multiple_attestations(request, event_loop):
202204

203205
message = await msg_buffer.msg_queue.get()
204206
assert isinstance(message.command, Attestations)
205-
assert message.payload == tuple(ssz.encode(attestation) for attestation in attestations)
207+
assert message.payload["encoded_attestations"] == tuple(
208+
ssz.encode(attestation) for attestation in attestations)

tests/plugins/eth2/beacon/test_receive_server.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,29 @@
1717
MsgBuffer,
1818
)
1919

20+
from eth.constants import (
21+
ZERO_HASH32,
22+
)
2023
from eth.exceptions import (
2124
BlockNotFound,
2225
)
2326

27+
from eth2.beacon.typing import (
28+
FromBlockParams,
29+
)
2430
from eth2.beacon.chains.testnet import TestnetChain
31+
from eth2.beacon.types.attestations import Attestation
32+
from eth2.beacon.types.attestation_data import AttestationData
2533
from eth2.beacon.types.blocks import (
2634
BaseBeaconBlock,
2735
)
28-
from eth2.beacon.typing import (
29-
FromBlockParams,
30-
)
36+
from eth2.beacon.types.crosslinks import Crosslink
3137
from eth2.beacon.state_machines.forks.serenity.blocks import (
3238
SerenityBeaconBlock,
3339
)
3440
from eth2.beacon.state_machines.forks.xiao_long_bao.configs import (
3541
XIAO_LONG_BAO_CONFIG,
3642
)
37-
3843
from trinity.protocol.bcc.peer import (
3944
BCCPeer,
4045
)
@@ -469,3 +474,44 @@ async def test_bcc_receive_server_with_request_server(request, event_loop):
469474
assert bob_recv_server._is_block_root_in_db(blocks[0].signing_root)
470475
assert bob_recv_server._is_block_root_in_db(blocks[1].signing_root)
471476
assert bob_recv_server._is_block_root_in_db(blocks[2].signing_root)
477+
478+
479+
@pytest.mark.asyncio
480+
async def test_bcc_receive_server_handle_attestations_checks(request, event_loop, monkeypatch):
481+
alice, _, bob_recv_server, bob_msg_queue = await get_peer_and_receive_server(
482+
request,
483+
event_loop,
484+
)
485+
attestation = Attestation(
486+
aggregation_bitfield=b'\x12' * 16,
487+
data=AttestationData(
488+
slot=XIAO_LONG_BAO_CONFIG.GENESIS_SLOT + 1,
489+
beacon_block_root=ZERO_HASH32,
490+
source_epoch=XIAO_LONG_BAO_CONFIG.GENESIS_EPOCH,
491+
source_root=ZERO_HASH32,
492+
target_root=ZERO_HASH32,
493+
shard=0,
494+
previous_crosslink=Crosslink(
495+
epoch=XIAO_LONG_BAO_CONFIG.GENESIS_EPOCH,
496+
crosslink_data_root=ZERO_HASH32,
497+
),
498+
crosslink_data_root=ZERO_HASH32,
499+
),
500+
custody_bitfield=b'\x34' * 16,
501+
aggregate_signature=b'\x56' * 96,
502+
)
503+
504+
def _validate_attestations(attestations):
505+
return tuple(attestations)
506+
507+
monkeypatch.setattr(
508+
bob_recv_server,
509+
'_validate_attestations',
510+
_validate_attestations,
511+
)
512+
513+
alice.sub_proto.send_attestation_records([attestation])
514+
msg = await bob_msg_queue.get()
515+
assert len(msg['encoded_attestations']) == 1
516+
decoded_attestation = ssz.decode(msg['encoded_attestations'][0], Attestation)
517+
assert decoded_attestation == attestation

0 commit comments

Comments
 (0)