From 0764d19ec43b8428ba046290c66bd90796665b2e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 19 Dec 2019 00:20:29 +0800 Subject: [PATCH 1/2] Fix `InvalidGossipMessage` messages --- .../protocol/bcc_libp2p/topic_validators.py | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/trinity/protocol/bcc_libp2p/topic_validators.py b/trinity/protocol/bcc_libp2p/topic_validators.py index d8fcbcb0c9..66346bc1a9 100644 --- a/trinity/protocol/bcc_libp2p/topic_validators.py +++ b/trinity/protocol/bcc_libp2p/topic_validators.py @@ -49,7 +49,7 @@ def beacon_block_validator(msg_forwarder: ID, msg: rpc_pb2.Message) -> bool: block = ssz.decode(msg.data, BeaconBlock) except (TypeError, ssz.DeserializationError) as error: logger.debug( - bold_red("Failed to decode block=%s, error=%s"), + bold_red("Failed to deserialize BeaconBlock from %s, error=%s"), encode_hex(msg.data), str(error), ) @@ -77,7 +77,7 @@ def beacon_attestation_validator(msg_forwarder: ID, msg: rpc_pb2.Message) -> boo except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( - bold_red("Failed to validate attestation=%s, error=%s"), + bold_red("Failed to deserialize Attestation from %s, error=%s"), encode_hex(msg.data), str(error), ) @@ -113,7 +113,7 @@ def committee_index_beacon_attestation_validator( except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( - bold_red("Failed to validate attestation=%s, error=%s"), + bold_red("Failed to deserialize Attestation from %s, error=%s"), encode_hex(msg.data), str(error), ) @@ -152,7 +152,7 @@ def beacon_aggregate_and_proof_validator(msg_forwarder: ID, msg: rpc_pb2.Message except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( - bold_red("Failed to validate aggregate_and_proof=%s, error=%s"), + bold_red("Failed to deserialize AggregateAndProof from %s, error=%s"), encode_hex(msg.data), str(error), ) @@ -194,28 +194,24 @@ def run_validate_block_proposer_signature( ) except ValidationError as error: raise InvalidGossipMessage( - "Failed to fast forward to state at slot=%d, error=%s", - block.slot, - str(error), + f"Failed to fast forward to state at slot={block.slot}", + error, ) try: validate_proposer_signature(future_state, block, CommitteeConfig(state_machine.config)) except ValidationError as error: - logger.debug( - "Failed to validate block=%s, error=%s", - encode_hex(block.signing_root), - str(error), + raise InvalidGossipMessage( + f"Failed to validate block={encode_hex(block.signing_root)}", + error, ) def validate_subnet_id(attestation: Attestation, subnet_id: SubnetId) -> None: if attestation.data.index % ATTESTATION_SUBNET_COUNT != subnet_id: raise InvalidGossipMessage( - "Wrong attestation subnet_id=%d, topic subnet_id=%d. Attestation: %s", - attestation.data.index % ATTESTATION_SUBNET_COUNT, - subnet_id, - attestation, + f"Wrong attestation subnet_id={attestation.data.index % ATTESTATION_SUBNET_COUNT}," + f" topic subnet_id={subnet_id}. Attestation: {attestation}" ) @@ -223,8 +219,7 @@ def validate_is_unaggregated(attestation: Attestation) -> None: # Check if the attestation is unaggregated if len([bit for bit in attestation.aggregation_bits if bit is True]) != 1: raise InvalidGossipMessage( - "The attestation is aggregated. Attestation: %s", - attestation, + f"The attestation is aggregated. Attestation: {attestation}" ) return False @@ -235,9 +230,9 @@ def validate_voting_beacon_block(chain: BaseBeaconChain, attestation: Attestatio chain.get_block_by_root(attestation.data.beacon_block_root) except BlockNotFound: raise InvalidGossipMessage( - "Failed to validate attestation=%s, attested block=%s is not validated yet", - attestation, - encode_hex(attestation.data.beacon_block_root), + f"Failed to validate attestation={attestation}," + f" attested block={encode_hex(attestation.data.beacon_block_root)}" + " has not been not validated yet" ) @@ -254,8 +249,7 @@ def run_validate_aggregate_and_proof( config, ) except ValidationError as error: - InvalidGossipMessage( - "Failed to validate aggregate_and_proof=%s, error=%s", - aggregate_and_proof, - str(error), + raise InvalidGossipMessage( + f"Failed to validate aggregate_and_proof={aggregate_and_proof}", + error, ) From d9232999c1722d5a5cf919259fdcf90fad0a2975 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 19 Dec 2019 15:20:43 +0800 Subject: [PATCH 2/2] Bugfix: only broadcast unaggregated attestation in subnets --- eth2/beacon/tools/builder/validator.py | 90 ++++++++++++++++--- .../components/eth2/beacon/test_validator.py | 2 +- trinity/components/eth2/beacon/validator.py | 11 +-- 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/eth2/beacon/tools/builder/validator.py b/eth2/beacon/tools/builder/validator.py index 183334f9a6..8b4ccf10c8 100644 --- a/eth2/beacon/tools/builder/validator.py +++ b/eth2/beacon/tools/builder/validator.py @@ -527,28 +527,19 @@ def _create_mock_signed_attestation( ) -def create_signed_attestation_at_slot( +def create_atteatsion_data( state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, attestation_slot: Slot, beacon_block_root: SigningRoot, - validator_privkeys: Dict[ValidatorIndex, int], - committee: Tuple[ValidatorIndex, ...], committee_index: CommitteeIndex, - attesting_indices: Sequence[CommitteeValidatorIndex], -) -> Attestation: - """ - Create the attestations of the given ``attestation_slot`` slot with ``validator_privkeys``. - """ - state_transition = state_machine.state_transition - state = state_transition.apply_state_transition(state, future_slot=attestation_slot) - +) -> AttestationData: target_epoch = compute_epoch_at_slot(attestation_slot, config.SLOTS_PER_EPOCH) target_root = _get_target_root(state, config, beacon_block_root) - attestation_data = AttestationData.create( + return AttestationData.create( slot=attestation_slot, index=committee_index, beacon_block_root=beacon_block_root, @@ -559,6 +550,81 @@ def create_signed_attestation_at_slot( target=Checkpoint.create(root=target_root, epoch=target_epoch), ) + +@to_tuple +def create_signed_attestations_at_slot( + state: BeaconState, + config: Eth2Config, + state_machine: BaseBeaconStateMachine, + attestation_slot: Slot, + beacon_block_root: SigningRoot, + validator_privkeys: Dict[ValidatorIndex, int], + committee: Tuple[ValidatorIndex, ...], + committee_index: CommitteeIndex, + attesting_indices: Sequence[CommitteeValidatorIndex], +) -> Iterable[Attestation]: + """ + Create the attestations of the given ``attestation_slot`` slot with ``validator_privkeys``. + """ + state_transition = state_machine.state_transition + state = state_transition.apply_state_transition(state, future_slot=attestation_slot) + + attestation_data = create_atteatsion_data( + state, + config, + state_machine, + attestation_slot, + beacon_block_root, + committee_index, + ) + + validator_indices = tuple(validator_privkeys) + for index, committee_validator_index in enumerate(attesting_indices): + validator_index = validator_indices[index] + yield _create_mock_signed_attestation( + state, + attestation_data, + attestation_slot, + committee, + len(committee), + { + state.validators[validator_index].pubkey: validator_privkeys[ + validator_index + ] + }, + config.SLOTS_PER_EPOCH, + is_for_simulation=False, + attesting_indices=(committee_validator_index,), + ) + + +def create_signed_attestation_at_slot( + state: BeaconState, + config: Eth2Config, + state_machine: BaseBeaconStateMachine, + attestation_slot: Slot, + beacon_block_root: SigningRoot, + validator_privkeys: Dict[ValidatorIndex, int], + committee: Tuple[ValidatorIndex, ...], + committee_index: CommitteeIndex, + attesting_indices: Sequence[CommitteeValidatorIndex], +) -> Attestation: + """ + Create the aggregated attestation of the given ``attestation_slot`` slot + of the given committee. + """ + state_transition = state_machine.state_transition + state = state_transition.apply_state_transition(state, future_slot=attestation_slot) + + attestation_data = create_atteatsion_data( + state, + config, + state_machine, + attestation_slot, + beacon_block_root, + committee_index, + ) + return _create_mock_signed_attestation( state, attestation_data, diff --git a/tests/components/eth2/beacon/test_validator.py b/tests/components/eth2/beacon/test_validator.py index 9aafc41d08..8651170d27 100644 --- a/tests/components/eth2/beacon/test_validator.py +++ b/tests/components/eth2/beacon/test_validator.py @@ -377,7 +377,7 @@ async def test_validator_attest(event_loop, event_bus): assignment = alice._get_local_current_epoch_assignment(alice_indices[0], epoch) attestations = await alice.attest(assignment.slot) - assert len(attestations) == 1 + assert len(attestations) >= 1 attestation = attestations[0] assert attestation.data.slot == assignment.slot assert attestation.data.beacon_block_root == head.signing_root diff --git a/trinity/components/eth2/beacon/validator.py b/trinity/components/eth2/beacon/validator.py index 5251101a14..a1b6a41ee5 100644 --- a/trinity/components/eth2/beacon/validator.py +++ b/trinity/components/eth2/beacon/validator.py @@ -49,7 +49,7 @@ get_committee_assignment, ) from eth2.beacon.tools.builder.validator import ( - create_signed_attestation_at_slot, + create_signed_attestations_at_slot, ) from eth2.beacon.types.aggregate_and_proof import ( AggregateAndProof, @@ -416,7 +416,7 @@ async def attest(self, slot: Slot) -> Tuple[Attestation, ...]: index: self.validator_privkeys[index] for index in attesting_validators_indices } - attestation = create_signed_attestation_at_slot( + attestations = create_signed_attestations_at_slot( state, state_machine.config, state_machine, @@ -434,15 +434,16 @@ async def attest(self, slot: Slot) -> Tuple[Attestation, ...]: bold_green("validators %s attesting to block %s with attestation %s"), attesting_validators_indices, head, - attestation, + attestations, ) # await self.p2p_node.broadcast_attestation(attestation) subnet_id = SubnetId(committee_index % ATTESTATION_SUBNET_COUNT) # Import attestation to pool and then broadcast it - self.import_attestation(attestation, False) - await self.p2p_node.broadcast_attestation_to_subnet(attestation, subnet_id) + for attestation in attestations: + self.import_attestation(attestation, False) + await self.p2p_node.broadcast_attestation_to_subnet(attestation, subnet_id) # Log the last epoch that the validator attested for index in attesting_validators_indices: