diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java index f279cbf2a66..a71c12a3d1d 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java @@ -126,11 +126,6 @@ public UInt64 computeTimeAtSlot(final UInt64 genesisTime, final UInt64 slot) { return genesisTime.plus(slot.times(specConfig.getSecondsPerSlot())); } - public UInt64 computeStartTimeAtEpoch(final UInt64 genesisTime, final UInt64 epoch) { - final UInt64 epochStartSlot = computeStartSlotAtEpoch(epoch); - return computeTimeAtSlot(genesisTime, epochStartSlot); - } - public UInt64 computeTimeAtSlot(final BeaconState state, final UInt64 slot) { UInt64 slotsSinceGenesis = slot.minus(SpecConfig.GENESIS_SLOT); return state.getGenesisTime().plus(slotsSinceGenesis.times(specConfig.getSecondsPerSlot())); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/AttestationUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/AttestationUtil.java index 55693edc81b..1fbaee9447a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/AttestationUtil.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/AttestationUtil.java @@ -303,6 +303,9 @@ public abstract AttestationWorthinessChecker createAttestationWorthinessChecker( performSlotInclusionGossipValidation( Attestation attestation, UInt64 genesisTime, UInt64 currentTimeMillis); + public abstract Optional + performSlotInclusionGossipValidation(Attestation attestation, BeaconState state); + public enum SlotInclusionGossipValidationResult { IGNORE, SAVE_FOR_FUTURE diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/util/AttestationUtilDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/util/AttestationUtilDeneb.java index b478e8b9977..ecf939672b7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/util/AttestationUtilDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/util/AttestationUtilDeneb.java @@ -19,6 +19,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfig; import tech.pegasys.teku.spec.datastructures.operations.Attestation; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateAccessors; import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; import tech.pegasys.teku.spec.logic.versions.altair.util.AttestationUtilAltair; @@ -35,17 +36,9 @@ public AttestationUtilDeneb( } /** - * - * - * + * [IGNORE] attestation.data.slot is equal to or earlier than the current_slot (with a + * MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. attestation.data.slot <= current_slot (a + * client MAY queue future attestation for processing at the appropriate slot). */ @Override public Optional performSlotInclusionGossipValidation( @@ -55,9 +48,6 @@ public Optional performSlotInclusionGossipV && isFromFarFuture(attestation, genesisTime, currentTimeMillis)) { return Optional.of(SlotInclusionGossipValidationResult.IGNORE); } - if (!isAttestationSlotCurrentOrPreviousEpoch(attestationSlot, genesisTime, currentTimeMillis)) { - return Optional.of(SlotInclusionGossipValidationResult.IGNORE); - } if (isCurrentTimeBeforeMinimumAttestationBroadcastTime( attestationSlot, genesisTime, currentTimeMillis)) { return Optional.of(SlotInclusionGossipValidationResult.SAVE_FOR_FUTURE); @@ -65,6 +55,23 @@ && isFromFarFuture(attestation, genesisTime, currentTimeMillis)) { return Optional.empty(); } + /** + * [IGNORE] the epoch of aggregate.data.slot is either the current or previous epoch (with a + * MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. compute_epoch_at_slot(aggregate.data.slot) in + * (get_previous_epoch(state), get_current_epoch(state)) + */ + @Override + public Optional performSlotInclusionGossipValidation( + final Attestation attestation, final BeaconState state) { + final UInt64 attestationEpoch = miscHelpers.computeEpochAtSlot(attestation.getData().getSlot()); + + if (attestationEpoch.isGreaterThanOrEqualTo(beaconStateAccessors.getPreviousEpoch(state)) + && attestationEpoch.isLessThanOrEqualTo(beaconStateAccessors.getCurrentEpoch(state))) { + return Optional.of(SlotInclusionGossipValidationResult.IGNORE); + } + return Optional.empty(); + } + private boolean isAttestationSlotAfterCurrentTime( final UInt64 attestationSlot, final UInt64 genesisTime, final UInt64 currentTimeMillis) { final UInt64 attestationSlotTimeMillis = @@ -72,19 +79,4 @@ private boolean isAttestationSlotAfterCurrentTime( return attestationSlotTimeMillis.isGreaterThan( currentTimeMillis.plus(specConfig.getMaximumGossipClockDisparity())); } - - private boolean isAttestationSlotCurrentOrPreviousEpoch( - final UInt64 attestationSlot, final UInt64 genesisTime, final UInt64 currentTimeMillis) { - final UInt64 attestationEpoch = miscHelpers.computeEpochAtSlot(attestationSlot); - final UInt64 nextEpochStartTimeMillis = - secondsToMillis(miscHelpers.computeStartTimeAtEpoch(genesisTime, attestationEpoch.plus(1))); - final UInt64 previousEpochStartTimeMillis = - secondsToMillis( - miscHelpers.computeStartTimeAtEpoch(genesisTime, attestationEpoch.minusMinZero(1))); - return currentTimeMillis - .minusMinZero(specConfig.getMaximumGossipClockDisparity()) - .isGreaterThanOrEqualTo(previousEpochStartTimeMillis) - && currentTimeMillis.isLessThan( - nextEpochStartTimeMillis.plus(specConfig.getMaximumGossipClockDisparity())); - } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/util/AttestationUtilPhase0.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/util/AttestationUtilPhase0.java index ad30bfda7c6..1397644e3ee 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/util/AttestationUtilPhase0.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/util/AttestationUtilPhase0.java @@ -67,6 +67,12 @@ public Optional performSlotInclusionGossipV return Optional.empty(); } + @Override + public Optional performSlotInclusionGossipValidation( + final Attestation attestation, final BeaconState state) { + return Optional.empty(); + } + protected boolean isCurrentTimeBeforeMinimumAttestationBroadcastTime( final UInt64 attestationSlot, final UInt64 genesisTime, final UInt64 currentTimeMillis) { final UInt64 minimumBroadcastTimeMillis = diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/AttestationValidator.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/AttestationValidator.java index 27e7785fc85..9ebd1a1b5bf 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/AttestationValidator.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/AttestationValidator.java @@ -28,6 +28,7 @@ import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.logic.common.util.AsyncBLSSignatureVerifier; +import tech.pegasys.teku.spec.logic.common.util.AttestationUtil; import tech.pegasys.teku.spec.logic.common.util.AttestationUtil.SlotInclusionGossipValidationResult; import tech.pegasys.teku.storage.client.RecentChainData; @@ -99,10 +100,11 @@ SafeFuture singleOrAggregateAttestationChecks final UInt64 genesisTime = recentChainData.getGenesisTime(); final UInt64 currentTimeMillis = recentChainData.getStore().getTimeMillis(); + final AttestationUtil attestationUtil = spec.atSlot(data.getSlot()).getAttestationUtil(); + final Optional slotInclusionGossipValidationResult = - spec.atSlot(data.getSlot()) - .getAttestationUtil() - .performSlotInclusionGossipValidation(attestation, genesisTime, currentTimeMillis); + attestationUtil.performSlotInclusionGossipValidation( + attestation, genesisTime, currentTimeMillis); if (slotInclusionGossipValidationResult.isPresent()) { switch (slotInclusionGossipValidationResult.get()) { @@ -130,6 +132,20 @@ SafeFuture singleOrAggregateAttestationChecks return completedFuture(InternalValidationResultWithState.ignore()); } final BeaconState state = maybeState.get(); + + final Optional + slotInclusionGossipValidationWithStateResult = + attestationUtil.performSlotInclusionGossipValidation(attestation, state); + + if (slotInclusionGossipValidationWithStateResult.isPresent()) { + switch (slotInclusionGossipValidationWithStateResult.get()) { + case IGNORE: + return completedFuture(InternalValidationResultWithState.ignore()); + case SAVE_FOR_FUTURE: + break; + } + } + // The committee index is within the expected range if (data.getIndex() .isGreaterThanOrEqualTo(