diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidator.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidator.java index 0e5968a89c4..7812077bd95 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidator.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidator.java @@ -89,6 +89,18 @@ public SafeFuture validate(final SignedBlobSidecar sig tech.pegasys.teku.networking.eth2.gossip.BlobSidecarGossipManager.TopicSubnetIdAwareOperationProcessor */ + /* + [REJECT] The sidecar's index is consistent with `MAX_BLOBS_PER_BLOCK` -- i.e. `sidecar.index < MAX_BLOBS_PER_BLOCK` + */ + final Optional maxBlobsPerBlockAtSlot = + spec.getMaxBlobsPerBlock(blobSidecar.getSlot()); + if (maxBlobsPerBlockAtSlot.isEmpty()) { + return completedFuture(reject("BlobSidecar's slot is pre deneb")); + } + if (blobSidecar.getIndex().isGreaterThanOrEqualTo(maxBlobsPerBlockAtSlot.get())) { + return completedFuture(reject("BlobSidecar index is greater than MAX_BLOBS_PER_BLOCK")); + } + /* [REJECT] The sidecar's block's parent (defined by sidecar.block_parent_root) passes validation. */ diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidatorTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidatorTest.java index ee8b6065077..f57069c4b34 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidatorTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/validation/BlobSidecarValidatorTest.java @@ -27,6 +27,7 @@ import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.async.SafeFutureAssert; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecInvocationContextProvider.SpecContext; @@ -101,6 +102,36 @@ void shouldAccept() { .isCompletedWithValueMatching(InternalValidationResult::isAccept); } + @TestTemplate + void shouldRejectWhenIndexIsTooBig(final SpecContext specContext) { + + signedBlobSidecar = + specContext + .getDataStructureUtil() + .createRandomBlobSidecarBuilder() + .slot(slot) + .index(UInt64.valueOf(specContext.getSpec().getMaxBlobsPerBlock().orElseThrow())) + .proposerIndex(proposerIndex) + .blockRoot(blockRoot) + .blockParentRoot(blockParentRoot) + .buildSigned(); + + SafeFutureAssert.assertThatSafeFuture(blobSidecarValidator.validate(signedBlobSidecar)) + .isCompletedWithValueMatching(InternalValidationResult::isReject); + } + + @TestTemplate + void shouldRejectWhenSlotIsNotDeneb() { + final Spec mockedSpec = mock(Spec.class); + when(mockedSpec.getMaxBlobsPerBlock(slot)).thenReturn(Optional.empty()); + + blobSidecarValidator = + BlobSidecarValidator.create(mockedSpec, invalidBlocks, gossipValidationHelper); + + SafeFutureAssert.assertThatSafeFuture(blobSidecarValidator.validate(signedBlobSidecar)) + .isCompletedWithValueMatching(InternalValidationResult::isReject); + } + @TestTemplate void shouldRejectWhenParentBlockInvalid() { invalidBlocks.put(blockParentRoot, BlockImportResult.FAILED_INVALID_ANCESTRY);