diff --git a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRangeIntegrationTest.java b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRangeIntegrationTest.java index f538322ae6a..c727ad45b78 100644 --- a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRangeIntegrationTest.java +++ b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRangeIntegrationTest.java @@ -15,46 +15,63 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assumptions.assumeThat; import static tech.pegasys.teku.infrastructure.async.Waiter.waitFor; +import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA; +import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestTemplate; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.rpc.RpcResponseListener; -import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.TestSpecContext; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.generator.ChainBuilder; +@TestSpecContext(milestone = {CAPELLA, DENEB, ELECTRA}) public class BlobSidecarsByRangeIntegrationTest extends AbstractRpcMethodIntegrationTest { - @Test + private Eth2Peer peer; + private SpecMilestone specMilestone; + + @BeforeEach + public void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + peer = createPeer(specContext.getSpec()); + specMilestone = specContext.getSpecMilestone(); + } + + @TestTemplate public void requestBlobSidecars_shouldFailBeforeDenebMilestone() { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalCapella()); + assumeThat(specMilestone).isLessThan(SpecMilestone.DENEB); assertThatThrownBy(() -> requestBlobSidecarsByRange(peer, UInt64.ONE, UInt64.valueOf(10))) .hasRootCauseInstanceOf(UnsupportedOperationException.class) .hasMessageContaining("BlobSidecarsByRange method is not supported"); } - @Test - public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsOnDenebMilestone() + @TestTemplate + public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsAfterDenebMilestone() throws ExecutionException, InterruptedException, TimeoutException { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalDeneb()); + assumeThat(specMilestone).isGreaterThanOrEqualTo(DENEB); final List blobSidecars = requestBlobSidecarsByRange(peer, UInt64.ONE, UInt64.valueOf(10)); assertThat(blobSidecars).isEmpty(); } - @Test + @TestTemplate public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsWhenCountIsZero() throws ExecutionException, InterruptedException, TimeoutException { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalDeneb()); + assumeThat(specMilestone).isGreaterThanOrEqualTo(DENEB); // finalize chain 2 blobs per block finalizeChainWithBlobs(2); @@ -65,10 +82,10 @@ public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsWhenCountIsZero() assertThat(blobSidecars).isEmpty(); } - @Test + @TestTemplate public void requestBlobSidecars_shouldReturnCanonicalBlobSidecarsOnDenebMilestone() throws ExecutionException, InterruptedException, TimeoutException { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalDeneb()); + assumeThat(specMilestone).isGreaterThanOrEqualTo(DENEB); // finalize chain 2 blobs per block finalizeChainWithBlobs(2); diff --git a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRootIntegrationTest.java b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRootIntegrationTest.java index 85e37518598..3ed1ccd442a 100644 --- a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRootIntegrationTest.java +++ b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/BlobSidecarsByRootIntegrationTest.java @@ -15,7 +15,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assumptions.assumeThat; import static tech.pegasys.teku.infrastructure.async.Waiter.waitFor; +import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA; +import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import java.util.ArrayList; import java.util.List; @@ -24,46 +28,59 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes32; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestTemplate; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.rpc.RpcResponseListener; -import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.TestSpecContext; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; +@TestSpecContext(milestone = {CAPELLA, DENEB, ELECTRA}) public class BlobSidecarsByRootIntegrationTest extends AbstractRpcMethodIntegrationTest { - @Test + private Eth2Peer peer; + private SpecMilestone specMilestone; + + @BeforeEach + public void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + peer = createPeer(specContext.getSpec()); + specMilestone = specContext.getSpecMilestone(); + } + + @TestTemplate public void requestBlobSidecars_shouldFailBeforeDenebMilestone() { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalCapella()); + assumeThat(specMilestone).isLessThan(SpecMilestone.DENEB); assertThatThrownBy(() -> requestBlobSidecarsByRoot(peer, List.of())) .hasRootCauseInstanceOf(UnsupportedOperationException.class) .hasMessageContaining("BlobSidecarsByRoot method is not supported"); } - @Test + @TestTemplate public void requestBlobSidecar_shouldFailBeforeDenebMilestone() { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalCapella()); + assumeThat(specMilestone).isLessThan(SpecMilestone.DENEB); assertThatThrownBy( () -> requestBlobSidecarByRoot(peer, new BlobIdentifier(Bytes32.ZERO, UInt64.ZERO))) .hasRootCauseInstanceOf(UnsupportedOperationException.class) .hasMessageContaining("BlobSidecarsByRoot method is not supported"); } - @Test - public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsOnDenebMilestone() + @TestTemplate + public void requestBlobSidecars_shouldReturnEmptyBlobSidecarsAfterDenebMilestone() throws ExecutionException, InterruptedException, TimeoutException { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalDeneb()); + assumeThat(specMilestone).isGreaterThanOrEqualTo(DENEB); final Optional blobSidecar = requestBlobSidecarByRoot(peer, new BlobIdentifier(Bytes32.ZERO, UInt64.ZERO)); assertThat(blobSidecar).isEmpty(); } - @Test + @TestTemplate public void requestBlobSidecars_shouldReturnBlobSidecarsOnDenebMilestone() throws ExecutionException, InterruptedException, TimeoutException { - final Eth2Peer peer = createPeer(TestSpecFactory.createMinimalDeneb()); + assumeThat(specMilestone).isGreaterThanOrEqualTo(DENEB); // generate 4 blobs per block peerStorage.chainUpdater().blockOptions.setGenerateRandomBlobs(true); diff --git a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeListenerValidatingProxyTest.java b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeListenerValidatingProxyTest.java index f163cd802cb..4239cb6da0d 100644 --- a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeListenerValidatingProxyTest.java +++ b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeListenerValidatingProxyTest.java @@ -20,45 +20,66 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static tech.pegasys.teku.infrastructure.async.SafeFutureAssert.safeJoin; -import static tech.pegasys.teku.infrastructure.unsigned.UInt64.ONE; -import static tech.pegasys.teku.infrastructure.unsigned.UInt64.ZERO; import static tech.pegasys.teku.networking.eth2.rpc.beaconchain.methods.BlobSidecarsByRootValidatorTest.breakInclusionProof; +import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA; +import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.kzg.KZG; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.rpc.RpcResponseListener; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.util.DataStructureUtil; @SuppressWarnings("JavaCase") +@TestSpecContext(milestone = {DENEB, ELECTRA}) public class BlobSidecarsByRangeListenerValidatingProxyTest { - private final Spec spec = TestSpecFactory.createMainnetDeneb(); - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + + private final UInt64 currentForkEpoch = UInt64.valueOf(1); + private Spec spec; + private DataStructureUtil dataStructureUtil; + private UInt64 currentForkFirstSlot; private BlobSidecarsByRangeListenerValidatingProxy listenerWrapper; + private Integer maxBlobsPerBlock; private final Eth2Peer peer = mock(Eth2Peer.class); - private final Integer maxBlobsPerBlock = spec.getMaxBlobsPerBlock().orElseThrow(); private final KZG kzg = mock(KZG.class); @SuppressWarnings("unchecked") private final RpcResponseListener listener = mock(RpcResponseListener.class); @BeforeEach - void setUp() { + void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + spec = + switch (specContext.getSpecMilestone()) { + case PHASE0 -> throw new IllegalArgumentException("Phase0 is an unsupported milestone"); + case ALTAIR -> throw new IllegalArgumentException("Altair is an unsupported milestone"); + case BELLATRIX -> + throw new IllegalArgumentException("Bellatrix is an unsupported milestone"); + case CAPELLA -> throw new IllegalArgumentException("Capella is an unsupported milestone"); + case DENEB -> TestSpecFactory.createMinimalWithDenebForkEpoch(currentForkEpoch); + case ELECTRA -> TestSpecFactory.createMinimalWithElectraForkEpoch(currentForkEpoch); + }; + currentForkFirstSlot = spec.computeStartSlotAtEpoch(currentForkEpoch); + dataStructureUtil = new DataStructureUtil(spec); + maxBlobsPerBlock = spec.getMaxBlobsPerBlock().orElseThrow(); + when(listener.onResponse(any())).thenReturn(SafeFuture.completedFuture(null)); when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(true); } - @Test + @TestTemplate void blobSidecarFailsKzgVerification() { when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(false); - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -66,7 +87,7 @@ void blobSidecarFailsKzgVerification() { final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(ONE), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); final SafeFuture result = listenerWrapper.onResponse(blobSidecar1_0); assertThat(result).isCompletedExceptionally(); @@ -79,9 +100,9 @@ void blobSidecarFailsKzgVerification() { .describe()); } - @Test + @TestTemplate void blobSidecarFailsInclusionProofVerification() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -89,8 +110,8 @@ void blobSidecarFailsInclusionProofVerification() { final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(ONE), 0); - final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(spec, blobSidecar1_0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); + final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(blobSidecar1_0); final SafeFuture result = listenerWrapper.onResponse(blobSidecar1_0_modified); assertThat(result).isCompletedExceptionally(); @@ -103,9 +124,9 @@ void blobSidecarFailsInclusionProofVerification() { .describe()); } - @Test + @TestTemplate void blobSidecarSlotSmallerThanFromSlot() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot.plus(1); final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -113,7 +134,7 @@ void blobSidecarSlotSmallerThanFromSlot() { final BlobSidecar blobSidecar0_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(ZERO), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); final SafeFuture result = listenerWrapper.onResponse(blobSidecar0_0); assertThat(result).isCompletedExceptionally(); @@ -126,28 +147,35 @@ void blobSidecarSlotSmallerThanFromSlot() { .describe()); } - @Test + @TestTemplate void blobSidecarsSlotsAreCorrect() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( spec, peer, listener, maxBlobsPerBlock, kzg, startSlot, count); - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); final BlobSidecar blobSidecar1_1 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 1); final BlobSidecar blobSidecar2_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(2, block1.getRoot()), 0); + dataStructureUtil.randomSignedBeaconBlock( + currentForkFirstSlot.plus(1).longValue(), block1.getRoot()), + 0); final BlobSidecar blobSidecar3_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(3, blobSidecar2_0.getBlockRoot()), 0); + dataStructureUtil.randomSignedBeaconBlock( + currentForkFirstSlot.plus(2).longValue(), blobSidecar2_0.getBlockRoot()), + 0); final BlobSidecar blobSidecar4_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(4, blobSidecar3_0.getBlockRoot()), 0); + dataStructureUtil.randomSignedBeaconBlock( + currentForkFirstSlot.plus(3).longValue(), blobSidecar3_0.getBlockRoot()), + 0); assertDoesNotThrow(() -> listenerWrapper.onResponse(blobSidecar1_0).join()); assertDoesNotThrow(() -> listenerWrapper.onResponse(blobSidecar1_1).join()); @@ -156,9 +184,9 @@ void blobSidecarsSlotsAreCorrect() { assertDoesNotThrow(() -> listenerWrapper.onResponse(blobSidecar4_0).join()); } - @Test + @TestTemplate void blobSidecarSlotGreaterThanToSlot() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(8); // This requests 8 slots (1, 2, 3, 4, 5, 6, 7, 8) so 9 will be unexpected. listenerWrapper = @@ -167,19 +195,21 @@ void blobSidecarSlotGreaterThanToSlot() { final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(1), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); final BlobSidecar blobSidecar3_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(3), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(2)), 0); final BlobSidecar blobSidecar5_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(5), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(4)), 0); final BlobSidecar blobSidecar8_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(8), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(7)), 0); final BlobSidecar blobSidecar9_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(9, blobSidecar8_0.getBlockRoot()), 0); + dataStructureUtil.randomSignedBeaconBlock( + currentForkFirstSlot.plus(8).longValue(), blobSidecar8_0.getBlockRoot()), + 0); safeJoin(listenerWrapper.onResponse(blobSidecar1_0)); safeJoin(listenerWrapper.onResponse(blobSidecar3_0)); @@ -197,9 +227,9 @@ void blobSidecarSlotGreaterThanToSlot() { .describe()); } - @Test + @TestTemplate void blobSidecarParentRootDoesNotMatch() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -207,10 +237,10 @@ void blobSidecarParentRootDoesNotMatch() { final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(1), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); final BlobSidecar blobSidecar2_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(2), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(1)), 0); safeJoin(listenerWrapper.onResponse(blobSidecar1_0)); @@ -225,9 +255,9 @@ void blobSidecarParentRootDoesNotMatch() { .describe()); } - @Test + @TestTemplate void blobSidecarIndexIsGreaterOrEqualThanMaxBlobs() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = @@ -235,7 +265,7 @@ void blobSidecarIndexIsGreaterOrEqualThanMaxBlobs() { spec, peer, listener, maxBlobsPerBlock, kzg, startSlot, count); final SignedBeaconBlock block1 = - dataStructureUtil.randomSignedBeaconBlockWithCommitments(ONE, 7); + dataStructureUtil.randomSignedBeaconBlockWithCommitments(currentForkFirstSlot, 7); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); final BlobSidecar blobSidecar1_1 = @@ -269,9 +299,9 @@ void blobSidecarIndexIsGreaterOrEqualThanMaxBlobs() { .describe()); } - @Test + @TestTemplate void blobSidecarIndexIsInTheSameBlockButNotNext() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = @@ -279,7 +309,7 @@ void blobSidecarIndexIsInTheSameBlockButNotNext() { spec, peer, listener, maxBlobsPerBlock, kzg, startSlot, count); final SignedBeaconBlock block1 = - dataStructureUtil.randomSignedBeaconBlockWithCommitments(ONE, 3); + dataStructureUtil.randomSignedBeaconBlockWithCommitments(currentForkFirstSlot, 3); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); final BlobSidecar blobSidecar1_2 = @@ -298,32 +328,33 @@ void blobSidecarIndexIsInTheSameBlockButNotNext() { .describe()); } - @Test + @TestTemplate void isFirstBlobSidecarAfterAnEmptyBlobsBlock() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( spec, peer, listener, maxBlobsPerBlock, kzg, startSlot, count); - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); final BlobSidecar blobSidecar1_1 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 1); final BlobSidecar blobSidecar3_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(3), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(3)), 0); safeJoin(listenerWrapper.onResponse(blobSidecar1_0)); safeJoin(listenerWrapper.onResponse(blobSidecar1_1)); safeJoin(listenerWrapper.onResponse(blobSidecar3_0)); } - @Test + @TestTemplate void firstBlobSidecarIndexIsINotZero() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -331,7 +362,7 @@ void firstBlobSidecarIndexIsINotZero() { final BlobSidecar blobSidecar1_1 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(2), 1); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(1)), 1); final SafeFuture result = listenerWrapper.onResponse(blobSidecar1_1); assertThat(result).isCompletedExceptionally(); @@ -344,9 +375,9 @@ void firstBlobSidecarIndexIsINotZero() { .describe()); } - @Test + @TestTemplate void firstBlobSidecarIndexInNextBlockIsNotZero() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -354,10 +385,12 @@ void firstBlobSidecarIndexInNextBlockIsNotZero() { final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(1), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); final BlobSidecar blobSidecar2_1 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(2, blobSidecar1_0.getBlockRoot(), true), 1); + dataStructureUtil.randomSignedBeaconBlock( + currentForkFirstSlot.plus(1).longValue(), blobSidecar1_0.getBlockRoot(), true), + 1); assertDoesNotThrow(() -> listenerWrapper.onResponse(blobSidecar1_0).join()); @@ -372,9 +405,9 @@ void firstBlobSidecarIndexInNextBlockIsNotZero() { .describe()); } - @Test + @TestTemplate void blobSidecarUnexpectedSlot() { - final UInt64 startSlot = UInt64.valueOf(1); + final UInt64 startSlot = currentForkFirstSlot; final UInt64 count = UInt64.valueOf(4); listenerWrapper = new BlobSidecarsByRangeListenerValidatingProxy( @@ -382,10 +415,10 @@ void blobSidecarUnexpectedSlot() { final BlobSidecar blobSidecar2_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(2), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(1)), 0); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock( - dataStructureUtil.randomSignedBeaconBlock(1), 0); + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot), 0); safeJoin(listenerWrapper.onResponse(blobSidecar2_0)); final SafeFuture result = listenerWrapper.onResponse(blobSidecar1_0); diff --git a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootListenerValidatingProxyTest.java b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootListenerValidatingProxyTest.java index cfabe5c4a3a..fee98545ed5 100644 --- a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootListenerValidatingProxyTest.java +++ b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootListenerValidatingProxyTest.java @@ -20,45 +20,70 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static tech.pegasys.teku.networking.eth2.rpc.beaconchain.methods.BlobSidecarsByRootValidatorTest.breakInclusionProof; +import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import java.util.List; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.kzg.KZG; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.rpc.RpcResponseListener; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; import tech.pegasys.teku.spec.util.DataStructureUtil; @SuppressWarnings("JavaCase") +@TestSpecContext(milestone = {DENEB, ELECTRA}) public class BlobSidecarsByRootListenerValidatingProxyTest { - private final Spec spec = TestSpecFactory.createMainnetDeneb(); - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); - private BlobSidecarsByRootListenerValidatingProxy listenerWrapper; + + private final UInt64 currentForkEpoch = UInt64.valueOf(1); private final Eth2Peer peer = mock(Eth2Peer.class); private final KZG kzg = mock(KZG.class); @SuppressWarnings("unchecked") private final RpcResponseListener listener = mock(RpcResponseListener.class); + private Spec spec; + private DataStructureUtil dataStructureUtil; + private UInt64 currentForkFirstSlot; + private BlobSidecarsByRootListenerValidatingProxy listenerWrapper; + @BeforeEach - void setUp() { + void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + spec = + switch (specContext.getSpecMilestone()) { + case PHASE0 -> throw new IllegalArgumentException("Phase0 is an unsupported milestone"); + case ALTAIR -> throw new IllegalArgumentException("Altair is an unsupported milestone"); + case BELLATRIX -> + throw new IllegalArgumentException("Bellatrix is an unsupported milestone"); + case CAPELLA -> throw new IllegalArgumentException("Capella is an unsupported milestone"); + case DENEB -> TestSpecFactory.createMinimalWithDenebForkEpoch(currentForkEpoch); + case ELECTRA -> TestSpecFactory.createMinimalWithElectraForkEpoch(currentForkEpoch); + }; + dataStructureUtil = new DataStructureUtil(spec); + currentForkFirstSlot = spec.computeStartSlotAtEpoch(currentForkEpoch); when(listener.onResponse(any())).thenReturn(SafeFuture.completedFuture(null)); when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(true); } - @Test + @TestTemplate void blobSidecarsAreCorrect() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); - final SignedBeaconBlock block2 = dataStructureUtil.randomSignedBeaconBlock(UInt64.valueOf(2)); - final SignedBeaconBlock block3 = dataStructureUtil.randomSignedBeaconBlock(UInt64.valueOf(3)); - final SignedBeaconBlock block4 = dataStructureUtil.randomSignedBeaconBlock(UInt64.valueOf(4)); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); + final SignedBeaconBlock block2 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(1)); + final SignedBeaconBlock block3 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(2)); + final SignedBeaconBlock block4 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(3)); final List blobIdentifiers = List.of( new BlobIdentifier(block1.getRoot(), UInt64.ZERO), @@ -88,10 +113,12 @@ void blobSidecarsAreCorrect() { assertDoesNotThrow(() -> listenerWrapper.onResponse(blobSidecar4_0).join()); } - @Test + @TestTemplate void blobSidecarIdentifierNotRequested() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); - final SignedBeaconBlock block2 = dataStructureUtil.randomSignedBeaconBlock(UInt64.valueOf(2)); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); + final SignedBeaconBlock block2 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot.plus(1)); final List blobIdentifiers = List.of( new BlobIdentifier(block1.getRoot(), UInt64.ZERO), @@ -119,11 +146,14 @@ void blobSidecarIdentifierNotRequested() { .describe()); } - @Test + @TestTemplate void blobSidecarFailsKzgVerification() { when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(false); - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); - final BlobIdentifier blobIdentifier = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); + final BlobIdentifier blobIdentifier = + new BlobIdentifier( + block1.getRoot(), spec.computeStartSlotAtEpoch(currentForkEpoch.minus(1))); listenerWrapper = new BlobSidecarsByRootListenerValidatingProxy( peer, spec, listener, kzg, List.of(blobIdentifier)); @@ -142,17 +172,20 @@ void blobSidecarFailsKzgVerification() { .describe()); } - @Test + @TestTemplate void blobSidecarFailsInclusionProofVerification() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); - final BlobIdentifier blobIdentifier = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); + final BlobIdentifier blobIdentifier = + new BlobIdentifier( + block1.getRoot(), spec.computeStartSlotAtEpoch(currentForkEpoch.minus(1))); listenerWrapper = new BlobSidecarsByRootListenerValidatingProxy( peer, spec, listener, kzg, List.of(blobIdentifier)); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); - final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(spec, blobSidecar1_0); + final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(blobSidecar1_0); final SafeFuture result = listenerWrapper.onResponse(blobSidecar1_0_modified); assertThat(result).isCompletedExceptionally(); diff --git a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootValidatorTest.java b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootValidatorTest.java index 01548f8f016..b176a7a8f11 100644 --- a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootValidatorTest.java +++ b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootValidatorTest.java @@ -18,65 +18,58 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import java.util.List; import java.util.stream.IntStream; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.kzg.KZG; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; -import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; import tech.pegasys.teku.spec.util.DataStructureUtil; @SuppressWarnings("JavaCase") +@TestSpecContext(milestone = {DENEB, ELECTRA}) public class BlobSidecarsByRootValidatorTest { - private final Spec spec = TestSpecFactory.createMainnetDeneb(); - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); - private BlobSidecarsByRootValidator validator; + + private final UInt64 currentForkEpoch = UInt64.valueOf(1); private final Eth2Peer peer = mock(Eth2Peer.class); private final KZG kzg = mock(KZG.class); + private Spec spec; + private DataStructureUtil dataStructureUtil; + private BlobSidecarsByRootValidator validator; + private UInt64 currentForkFirstSlot; @BeforeEach - void setUp() { + void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + spec = + switch (specContext.getSpecMilestone()) { + case PHASE0 -> throw new IllegalArgumentException("Phase0 is an unsupported milestone"); + case ALTAIR -> throw new IllegalArgumentException("Altair is an unsupported milestone"); + case BELLATRIX -> + throw new IllegalArgumentException("Bellatrix is an unsupported milestone"); + case CAPELLA -> throw new IllegalArgumentException("Capella is an unsupported milestone"); + case DENEB -> TestSpecFactory.createMinimalWithDenebForkEpoch(currentForkEpoch); + case ELECTRA -> TestSpecFactory.createMinimalWithElectraForkEpoch(currentForkEpoch); + }; + currentForkFirstSlot = spec.computeStartSlotAtEpoch(currentForkEpoch); + dataStructureUtil = new DataStructureUtil(spec); when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(true); } - public static BlobSidecar breakInclusionProof(final Spec spec, final BlobSidecar blobSidecar) { - final BlobSidecar blobSidecarModified = - SchemaDefinitionsDeneb.required(spec.getGenesisSchemaDefinitions()) - .getBlobSidecarSchema() - .create( - blobSidecar.getIndex(), - blobSidecar.getBlob(), - blobSidecar.getKZGCommitment(), - blobSidecar.getKZGProof(), - blobSidecar.getSignedBeaconBlockHeader(), - IntStream.range(0, blobSidecar.getKzgCommitmentInclusionProof().size()) - .mapToObj( - index -> { - if (index == 0) { - return blobSidecar - .getKzgCommitmentInclusionProof() - .get(index) - .get() - .not(); - } else { - return blobSidecar.getKzgCommitmentInclusionProof().get(index).get(); - } - }) - .toList()); - return blobSidecarModified; - } - - @Test + @TestTemplate void blobSidecarIsCorrect() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobIdentifier blobIdentifier1_0 = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); @@ -85,9 +78,10 @@ void blobSidecarIsCorrect() { assertDoesNotThrow(() -> validator.validate(blobSidecar1_0)); } - @Test + @TestTemplate void blobSidecarIdentifierNotRequested() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobIdentifier blobIdentifier2_0 = new BlobIdentifier(dataStructureUtil.randomBytes32(), UInt64.ZERO); final BlobSidecar blobSidecar1_0 = @@ -102,10 +96,11 @@ void blobSidecarIdentifierNotRequested() { .describe()); } - @Test + @TestTemplate void blobSidecarFailsKzgVerification() { when(kzg.verifyBlobKzgProof(any(), any(), any())).thenReturn(false); - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobIdentifier blobIdentifier1_0 = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); @@ -119,13 +114,14 @@ void blobSidecarFailsKzgVerification() { .describe()); } - @Test + @TestTemplate void blobSidecarFailsInclusionProofVerification() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobIdentifier blobIdentifier1_0 = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); - final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(spec, blobSidecar1_0); + final BlobSidecar blobSidecar1_0_modified = breakInclusionProof(blobSidecar1_0); validator = new BlobSidecarsByRootValidator(peer, spec, kzg, List.of(blobIdentifier1_0)); assertThatThrownBy(() -> validator.validate(blobSidecar1_0_modified)) @@ -136,9 +132,10 @@ void blobSidecarFailsInclusionProofVerification() { .describe()); } - @Test + @TestTemplate void blobSidecarResponseWithDuplicateSidecar() { - final SignedBeaconBlock block1 = dataStructureUtil.randomSignedBeaconBlock(UInt64.ONE); + final SignedBeaconBlock block1 = + dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot); final BlobIdentifier blobIdentifier1_0 = new BlobIdentifier(block1.getRoot(), UInt64.ZERO); final BlobSidecar blobSidecar1_0 = dataStructureUtil.randomBlobSidecarWithValidInclusionProofForBlock(block1, 0); @@ -152,4 +149,25 @@ void blobSidecarResponseWithDuplicateSidecar() { .BLOB_SIDECAR_UNEXPECTED_IDENTIFIER .describe()); } + + public static BlobSidecar breakInclusionProof(final BlobSidecar blobSidecar) { + return blobSidecar + .getSchema() + .create( + blobSidecar.getIndex(), + blobSidecar.getBlob(), + blobSidecar.getKZGCommitment(), + blobSidecar.getKZGProof(), + blobSidecar.getSignedBeaconBlockHeader(), + IntStream.range(0, blobSidecar.getKzgCommitmentInclusionProof().size()) + .mapToObj( + index -> { + if (index == 0) { + return blobSidecar.getKzgCommitmentInclusionProof().get(index).get().not(); + } else { + return blobSidecar.getKzgCommitmentInclusionProof().get(index).get(); + } + }) + .toList()); + } }