@Test public void shouldRejectWhenAttestationValidatorSavesForFutureAndAggregateChecksFail() { final SignedAggregateAndProof aggregate = generator .generator() .blockAndState(recentChainData.getHeadBlockAndState().orElseThrow()) .aggregatorIndex(ONE) .selectionProof(dataStructureUtil.randomSignature()) .generate(); ValidateableAttestation attestation = ValidateableAttestation.fromSignedAggregate(aggregate); when(attestationValidator.singleOrAggregateAttestationChecks( eq(attestation), eq(OptionalInt.empty()))) .thenReturn(SafeFuture.completedFuture(SAVE_FOR_FUTURE)); assertThat(validator.validate(attestation)).isCompletedWithValue(REJECT); }
public SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation) { final SignedAggregateAndProof signedAggregate = attestation.getSignedAggregateAndProof(); final AggregateAndProof aggregateAndProof = signedAggregate.getMessage(); final Attestation aggregate = aggregateAndProof.getAggregate(); final UInt64 aggregateSlot = aggregate.getData().getSlot(); final AggregatorIndexAndEpoch aggregatorIndexAndEpoch = new AggregatorIndexAndEpoch( aggregateAndProof.getIndex(), compute_epoch_at_slot(aggregateSlot)); if (receivedAggregatorIndexAndEpochs.contains(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return SafeFuture.completedFuture(IGNORE); } if (receivedValidAggregations.contains(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return SafeFuture.completedFuture(IGNORE); } return attestationValidator .singleOrAggregateAttestationChecks(attestation, OptionalInt.empty()) .thenCompose( aggregateInternalValidationResult -> { if (aggregateInternalValidationResult == REJECT || aggregateInternalValidationResult == IGNORE) { LOG.trace("Rejecting aggregate because attestation failed validation"); return SafeFuture.completedFuture(aggregateInternalValidationResult); } return recentChainData .retrieveBlockState(aggregate.getData().getBeacon_block_root()) .thenCompose( maybeState -> maybeState.isEmpty() ? SafeFuture.completedFuture(Optional.empty()) : attestationValidator.resolveStateForAttestation( aggregate, maybeState.get())) .thenApply( maybeState -> { if (maybeState.isEmpty()) { return SAVE_FOR_FUTURE; } final BeaconState state = maybeState.get(); final Optional<BLSPublicKey> aggregatorPublicKey = ValidatorsUtil.getValidatorPubKey(state, aggregateAndProof.getIndex()); if (aggregatorPublicKey.isEmpty()) { LOG.trace("Rejecting aggregate with invalid index"); return REJECT; } if (!isSelectionProofValid( aggregateSlot, state, aggregatorPublicKey.get(), aggregateAndProof.getSelection_proof())) { LOG.trace("Rejecting aggregate with incorrect selection proof"); return REJECT; } final List<Integer> beaconCommittee = CommitteeUtil.get_beacon_committee( state, aggregateSlot, aggregate.getData().getIndex()); final int aggregatorModulo = getAggregatorModulo(beaconCommittee.size()); if (!isAggregator( aggregateAndProof.getSelection_proof(), aggregatorModulo)) { LOG.trace( "Rejecting aggregate because selection proof does not select validator as aggregator"); return REJECT; } if (!beaconCommittee.contains( toIntExact(aggregateAndProof.getIndex().longValue()))) { LOG.trace( "Rejecting aggregate because attester is not in committee. Should have been one of {}", beaconCommittee); return REJECT; } if (!isSignatureValid(signedAggregate, state, aggregatorPublicKey.get())) { LOG.trace("Rejecting aggregate with invalid signature"); return REJECT; } if (!receivedAggregatorIndexAndEpochs.add(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return IGNORE; } if (!receivedValidAggregations.add(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return IGNORE; } return aggregateInternalValidationResult; }); }); }
SignedAggregateAndProofValidator { public SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation) { final SignedAggregateAndProof signedAggregate = attestation.getSignedAggregateAndProof(); final AggregateAndProof aggregateAndProof = signedAggregate.getMessage(); final Attestation aggregate = aggregateAndProof.getAggregate(); final UInt64 aggregateSlot = aggregate.getData().getSlot(); final AggregatorIndexAndEpoch aggregatorIndexAndEpoch = new AggregatorIndexAndEpoch( aggregateAndProof.getIndex(), compute_epoch_at_slot(aggregateSlot)); if (receivedAggregatorIndexAndEpochs.contains(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return SafeFuture.completedFuture(IGNORE); } if (receivedValidAggregations.contains(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return SafeFuture.completedFuture(IGNORE); } return attestationValidator .singleOrAggregateAttestationChecks(attestation, OptionalInt.empty()) .thenCompose( aggregateInternalValidationResult -> { if (aggregateInternalValidationResult == REJECT || aggregateInternalValidationResult == IGNORE) { LOG.trace("Rejecting aggregate because attestation failed validation"); return SafeFuture.completedFuture(aggregateInternalValidationResult); } return recentChainData .retrieveBlockState(aggregate.getData().getBeacon_block_root()) .thenCompose( maybeState -> maybeState.isEmpty() ? SafeFuture.completedFuture(Optional.empty()) : attestationValidator.resolveStateForAttestation( aggregate, maybeState.get())) .thenApply( maybeState -> { if (maybeState.isEmpty()) { return SAVE_FOR_FUTURE; } final BeaconState state = maybeState.get(); final Optional<BLSPublicKey> aggregatorPublicKey = ValidatorsUtil.getValidatorPubKey(state, aggregateAndProof.getIndex()); if (aggregatorPublicKey.isEmpty()) { LOG.trace("Rejecting aggregate with invalid index"); return REJECT; } if (!isSelectionProofValid( aggregateSlot, state, aggregatorPublicKey.get(), aggregateAndProof.getSelection_proof())) { LOG.trace("Rejecting aggregate with incorrect selection proof"); return REJECT; } final List<Integer> beaconCommittee = CommitteeUtil.get_beacon_committee( state, aggregateSlot, aggregate.getData().getIndex()); final int aggregatorModulo = getAggregatorModulo(beaconCommittee.size()); if (!isAggregator( aggregateAndProof.getSelection_proof(), aggregatorModulo)) { LOG.trace( "Rejecting aggregate because selection proof does not select validator as aggregator"); return REJECT; } if (!beaconCommittee.contains( toIntExact(aggregateAndProof.getIndex().longValue()))) { LOG.trace( "Rejecting aggregate because attester is not in committee. Should have been one of {}", beaconCommittee); return REJECT; } if (!isSignatureValid(signedAggregate, state, aggregatorPublicKey.get())) { LOG.trace("Rejecting aggregate with invalid signature"); return REJECT; } if (!receivedAggregatorIndexAndEpochs.add(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return IGNORE; } if (!receivedValidAggregations.add(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return IGNORE; } return aggregateInternalValidationResult; }); }); } }
SignedAggregateAndProofValidator { public SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation) { final SignedAggregateAndProof signedAggregate = attestation.getSignedAggregateAndProof(); final AggregateAndProof aggregateAndProof = signedAggregate.getMessage(); final Attestation aggregate = aggregateAndProof.getAggregate(); final UInt64 aggregateSlot = aggregate.getData().getSlot(); final AggregatorIndexAndEpoch aggregatorIndexAndEpoch = new AggregatorIndexAndEpoch( aggregateAndProof.getIndex(), compute_epoch_at_slot(aggregateSlot)); if (receivedAggregatorIndexAndEpochs.contains(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return SafeFuture.completedFuture(IGNORE); } if (receivedValidAggregations.contains(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return SafeFuture.completedFuture(IGNORE); } return attestationValidator .singleOrAggregateAttestationChecks(attestation, OptionalInt.empty()) .thenCompose( aggregateInternalValidationResult -> { if (aggregateInternalValidationResult == REJECT || aggregateInternalValidationResult == IGNORE) { LOG.trace("Rejecting aggregate because attestation failed validation"); return SafeFuture.completedFuture(aggregateInternalValidationResult); } return recentChainData .retrieveBlockState(aggregate.getData().getBeacon_block_root()) .thenCompose( maybeState -> maybeState.isEmpty() ? SafeFuture.completedFuture(Optional.empty()) : attestationValidator.resolveStateForAttestation( aggregate, maybeState.get())) .thenApply( maybeState -> { if (maybeState.isEmpty()) { return SAVE_FOR_FUTURE; } final BeaconState state = maybeState.get(); final Optional<BLSPublicKey> aggregatorPublicKey = ValidatorsUtil.getValidatorPubKey(state, aggregateAndProof.getIndex()); if (aggregatorPublicKey.isEmpty()) { LOG.trace("Rejecting aggregate with invalid index"); return REJECT; } if (!isSelectionProofValid( aggregateSlot, state, aggregatorPublicKey.get(), aggregateAndProof.getSelection_proof())) { LOG.trace("Rejecting aggregate with incorrect selection proof"); return REJECT; } final List<Integer> beaconCommittee = CommitteeUtil.get_beacon_committee( state, aggregateSlot, aggregate.getData().getIndex()); final int aggregatorModulo = getAggregatorModulo(beaconCommittee.size()); if (!isAggregator( aggregateAndProof.getSelection_proof(), aggregatorModulo)) { LOG.trace( "Rejecting aggregate because selection proof does not select validator as aggregator"); return REJECT; } if (!beaconCommittee.contains( toIntExact(aggregateAndProof.getIndex().longValue()))) { LOG.trace( "Rejecting aggregate because attester is not in committee. Should have been one of {}", beaconCommittee); return REJECT; } if (!isSignatureValid(signedAggregate, state, aggregatorPublicKey.get())) { LOG.trace("Rejecting aggregate with invalid signature"); return REJECT; } if (!receivedAggregatorIndexAndEpochs.add(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return IGNORE; } if (!receivedValidAggregations.add(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return IGNORE; } return aggregateInternalValidationResult; }); }); } SignedAggregateAndProofValidator(
      final RecentChainData recentChainData, final AttestationValidator attestationValidator); }
SignedAggregateAndProofValidator { public SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation) { final SignedAggregateAndProof signedAggregate = attestation.getSignedAggregateAndProof(); final AggregateAndProof aggregateAndProof = signedAggregate.getMessage(); final Attestation aggregate = aggregateAndProof.getAggregate(); final UInt64 aggregateSlot = aggregate.getData().getSlot(); final AggregatorIndexAndEpoch aggregatorIndexAndEpoch = new AggregatorIndexAndEpoch( aggregateAndProof.getIndex(), compute_epoch_at_slot(aggregateSlot)); if (receivedAggregatorIndexAndEpochs.contains(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return SafeFuture.completedFuture(IGNORE); } if (receivedValidAggregations.contains(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return SafeFuture.completedFuture(IGNORE); } return attestationValidator .singleOrAggregateAttestationChecks(attestation, OptionalInt.empty()) .thenCompose( aggregateInternalValidationResult -> { if (aggregateInternalValidationResult == REJECT || aggregateInternalValidationResult == IGNORE) { LOG.trace("Rejecting aggregate because attestation failed validation"); return SafeFuture.completedFuture(aggregateInternalValidationResult); } return recentChainData .retrieveBlockState(aggregate.getData().getBeacon_block_root()) .thenCompose( maybeState -> maybeState.isEmpty() ? SafeFuture.completedFuture(Optional.empty()) : attestationValidator.resolveStateForAttestation( aggregate, maybeState.get())) .thenApply( maybeState -> { if (maybeState.isEmpty()) { return SAVE_FOR_FUTURE; } final BeaconState state = maybeState.get(); final Optional<BLSPublicKey> aggregatorPublicKey = ValidatorsUtil.getValidatorPubKey(state, aggregateAndProof.getIndex()); if (aggregatorPublicKey.isEmpty()) { LOG.trace("Rejecting aggregate with invalid index"); return REJECT; } if (!isSelectionProofValid( aggregateSlot, state, aggregatorPublicKey.get(), aggregateAndProof.getSelection_proof())) { LOG.trace("Rejecting aggregate with incorrect selection proof"); return REJECT; } final List<Integer> beaconCommittee = CommitteeUtil.get_beacon_committee( state, aggregateSlot, aggregate.getData().getIndex()); final int aggregatorModulo = getAggregatorModulo(beaconCommittee.size()); if (!isAggregator( aggregateAndProof.getSelection_proof(), aggregatorModulo)) { LOG.trace( "Rejecting aggregate because selection proof does not select validator as aggregator"); return REJECT; } if (!beaconCommittee.contains( toIntExact(aggregateAndProof.getIndex().longValue()))) { LOG.trace( "Rejecting aggregate because attester is not in committee. Should have been one of {}", beaconCommittee); return REJECT; } if (!isSignatureValid(signedAggregate, state, aggregatorPublicKey.get())) { LOG.trace("Rejecting aggregate with invalid signature"); return REJECT; } if (!receivedAggregatorIndexAndEpochs.add(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return IGNORE; } if (!receivedValidAggregations.add(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return IGNORE; } return aggregateInternalValidationResult; }); }); } SignedAggregateAndProofValidator(
      final RecentChainData recentChainData, final AttestationValidator attestationValidator); void addSeenAggregate(final ValidateableAttestation attestation); SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation); }
SignedAggregateAndProofValidator { public SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation) { final SignedAggregateAndProof signedAggregate = attestation.getSignedAggregateAndProof(); final AggregateAndProof aggregateAndProof = signedAggregate.getMessage(); final Attestation aggregate = aggregateAndProof.getAggregate(); final UInt64 aggregateSlot = aggregate.getData().getSlot(); final AggregatorIndexAndEpoch aggregatorIndexAndEpoch = new AggregatorIndexAndEpoch( aggregateAndProof.getIndex(), compute_epoch_at_slot(aggregateSlot)); if (receivedAggregatorIndexAndEpochs.contains(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return SafeFuture.completedFuture(IGNORE); } if (receivedValidAggregations.contains(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return SafeFuture.completedFuture(IGNORE); } return attestationValidator .singleOrAggregateAttestationChecks(attestation, OptionalInt.empty()) .thenCompose( aggregateInternalValidationResult -> { if (aggregateInternalValidationResult == REJECT || aggregateInternalValidationResult == IGNORE) { LOG.trace("Rejecting aggregate because attestation failed validation"); return SafeFuture.completedFuture(aggregateInternalValidationResult); } return recentChainData .retrieveBlockState(aggregate.getData().getBeacon_block_root()) .thenCompose( maybeState -> maybeState.isEmpty() ? SafeFuture.completedFuture(Optional.empty()) : attestationValidator.resolveStateForAttestation( aggregate, maybeState.get())) .thenApply( maybeState -> { if (maybeState.isEmpty()) { return SAVE_FOR_FUTURE; } final BeaconState state = maybeState.get(); final Optional<BLSPublicKey> aggregatorPublicKey = ValidatorsUtil.getValidatorPubKey(state, aggregateAndProof.getIndex()); if (aggregatorPublicKey.isEmpty()) { LOG.trace("Rejecting aggregate with invalid index"); return REJECT; } if (!isSelectionProofValid( aggregateSlot, state, aggregatorPublicKey.get(), aggregateAndProof.getSelection_proof())) { LOG.trace("Rejecting aggregate with incorrect selection proof"); return REJECT; } final List<Integer> beaconCommittee = CommitteeUtil.get_beacon_committee( state, aggregateSlot, aggregate.getData().getIndex()); final int aggregatorModulo = getAggregatorModulo(beaconCommittee.size()); if (!isAggregator( aggregateAndProof.getSelection_proof(), aggregatorModulo)) { LOG.trace( "Rejecting aggregate because selection proof does not select validator as aggregator"); return REJECT; } if (!beaconCommittee.contains( toIntExact(aggregateAndProof.getIndex().longValue()))) { LOG.trace( "Rejecting aggregate because attester is not in committee. Should have been one of {}", beaconCommittee); return REJECT; } if (!isSignatureValid(signedAggregate, state, aggregatorPublicKey.get())) { LOG.trace("Rejecting aggregate with invalid signature"); return REJECT; } if (!receivedAggregatorIndexAndEpochs.add(aggregatorIndexAndEpoch)) { LOG.trace("Ignoring duplicate aggregate"); return IGNORE; } if (!receivedValidAggregations.add(attestation.hash_tree_root())) { LOG.trace("Ignoring duplicate aggregate based on hash tree root"); return IGNORE; } return aggregateInternalValidationResult; }); }); } SignedAggregateAndProofValidator(
      final RecentChainData recentChainData, final AttestationValidator attestationValidator); void addSeenAggregate(final ValidateableAttestation attestation); SafeFuture<InternalValidationResult> validate(final ValidateableAttestation attestation);  }