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

Fix InvalidGossipMessage messages and co-attest #1406

Merged
merged 2 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 78 additions & 12 deletions eth2/beacon/tools/builder/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion tests/components/eth2/beacon/test_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions trinity/components/eth2/beacon/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand Down
42 changes: 18 additions & 24 deletions trinity/protocol/bcc_libp2p/topic_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
Expand Down Expand Up @@ -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),
)
Expand Down Expand Up @@ -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),
)
Expand Down Expand Up @@ -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),
)
Expand Down Expand Up @@ -194,37 +194,32 @@ 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}"
)


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

Expand All @@ -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"
)


Expand All @@ -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,
)