From 37c3683a408fb52701ca15ab91a3fd6d9f1835d4 Mon Sep 17 00:00:00 2001 From: Mehdi AOUADI Date: Tue, 5 Nov 2024 15:39:34 +0100 Subject: [PATCH 1/2] update blobs rpc methods --- .../rpc/beaconchain/BeaconChainMethods.java | 11 +- .../BlobSidecarsByRangeMessageHandler.java | 46 +++++--- .../BlobSidecarsByRootMessageHandler.java | 14 ++- ...BlobSidecarsByRangeMessageHandlerTest.java | 101 ++++++++--------- .../BlobSidecarsByRootMessageHandlerTest.java | 104 +++++++++++------- 5 files changed, 157 insertions(+), 119 deletions(-) diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/BeaconChainMethods.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/BeaconChainMethods.java index 631730f8ef9..63ba993db5f 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/BeaconChainMethods.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/BeaconChainMethods.java @@ -42,7 +42,6 @@ import tech.pegasys.teku.networking.p2p.rpc.RpcMethod; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; 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.BeaconBlocksByRangeRequestMessage; @@ -284,8 +283,7 @@ private static Eth2RpcMethod createGoodBye( RpcContextCodec.forkDigest(spec, recentChainData, ForkDigestPayloadContext.BLOB_SIDECAR); final BlobSidecarsByRootMessageHandler blobSidecarsByRootHandler = - new BlobSidecarsByRootMessageHandler( - spec, getSpecConfigDeneb(spec), metricsSystem, combinedChainDataClient); + new BlobSidecarsByRootMessageHandler(spec, metricsSystem, combinedChainDataClient); final BlobSidecarsByRootRequestMessageSchema blobSidecarsByRootRequestMessageSchema = SchemaDefinitionsDeneb.required( spec.forMilestone(SpecMilestone.DENEB).getSchemaDefinitions()) @@ -326,8 +324,7 @@ private static Eth2RpcMethod createGoodBye( RpcContextCodec.forkDigest(spec, recentChainData, ForkDigestPayloadContext.BLOB_SIDECAR); final BlobSidecarsByRangeMessageHandler blobSidecarsByRangeHandler = - new BlobSidecarsByRangeMessageHandler( - spec, getSpecConfigDeneb(spec), metricsSystem, combinedChainDataClient); + new BlobSidecarsByRangeMessageHandler(spec, metricsSystem, combinedChainDataClient); return Optional.of( new SingleProtocolEth2RpcMethod<>( @@ -426,10 +423,6 @@ private static Eth2RpcMethod createPing( spec.getNetworkingConfig()); } - private static SpecConfigDeneb getSpecConfigDeneb(final Spec spec) { - return SpecConfigDeneb.required(spec.forMilestone(SpecMilestone.DENEB).getConfig()); - } - public Collection> all() { return Collections.unmodifiableCollection(allMethods); } diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandler.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandler.java index 4012667c728..ca4a7b7c0c7 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandler.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandler.java @@ -41,10 +41,11 @@ import tech.pegasys.teku.networking.eth2.rpc.core.RpcException.ResourceUnavailableException; import tech.pegasys.teku.networking.p2p.rpc.StreamClosedException; import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobSidecarsByRangeRequestMessage; import tech.pegasys.teku.spec.datastructures.util.SlotAndBlockRootAndBlobIndex; +import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; import tech.pegasys.teku.storage.client.CombinedChainDataClient; /** @@ -58,18 +59,15 @@ public class BlobSidecarsByRangeMessageHandler private static final Logger LOG = LogManager.getLogger(); private final Spec spec; - private final SpecConfigDeneb specConfigDeneb; private final CombinedChainDataClient combinedChainDataClient; private final LabelledMetric requestCounter; private final Counter totalBlobSidecarsRequestedCounter; public BlobSidecarsByRangeMessageHandler( final Spec spec, - final SpecConfigDeneb specConfigDeneb, final MetricsSystem metricsSystem, final CombinedChainDataClient combinedChainDataClient) { this.spec = spec; - this.specConfigDeneb = specConfigDeneb; this.combinedChainDataClient = combinedChainDataClient; requestCounter = metricsSystem.createLabelledCounter( @@ -88,16 +86,23 @@ public BlobSidecarsByRangeMessageHandler( public Optional validateRequest( final String protocolId, final BlobSidecarsByRangeRequestMessage request) { - final long requestedCount = calculateRequestedCount(request); + final SpecMilestone latestMilestoneRequested = + spec.getForkSchedule().getSpecMilestoneAtSlot(request.getMaxSlot()); + final MiscHelpers miscHelpers = spec.forMilestone(latestMilestoneRequested).miscHelpers(); - if (requestedCount > specConfigDeneb.getMaxRequestBlobSidecars()) { + final int maxRequestBlobSidecars = miscHelpers.getMaxRequestBlobSidecars(); + final int maxBlobsPerBlock = miscHelpers.getMaxBlobsPerBlock(); + + final long requestedCount = calculateRequestedCount(request, maxBlobsPerBlock); + + if (requestedCount > maxRequestBlobSidecars) { requestCounter.labels("count_too_big").inc(); return Optional.of( new RpcException( INVALID_REQUEST_CODE, String.format( "Only a maximum of %s blob sidecars can be requested per request", - specConfigDeneb.getMaxRequestBlobSidecars()))); + maxRequestBlobSidecars))); } return Optional.empty(); @@ -118,7 +123,10 @@ public void onIncomingMessage( message.getCount(), startSlot); - final long requestedCount = calculateRequestedCount(message); + final SpecMilestone latestMilestoneRequested = + spec.getForkSchedule().getSpecMilestoneAtSlot(endSlot); + final MiscHelpers miscHelpers = spec.forMilestone(latestMilestoneRequested).miscHelpers(); + final long requestedCount = calculateRequestedCount(message, miscHelpers.getMaxBlobsPerBlock()); final Optional blobSidecarsRequestApproval = peer.approveBlobSidecarsRequest(callback, requestedCount); @@ -159,9 +167,15 @@ public void onIncomingMessage( } else { canonicalHotRoots = ImmutableSortedMap.of(); } - + final int maxRequestBlobSidecars = miscHelpers.getMaxRequestBlobSidecars(); final RequestState initialState = - new RequestState(callback, startSlot, endSlot, canonicalHotRoots, finalizedSlot); + new RequestState( + callback, + startSlot, + endSlot, + canonicalHotRoots, + finalizedSlot, + maxRequestBlobSidecars); if (message.getCount().isZero()) { return SafeFuture.completedFuture(initialState); } @@ -182,8 +196,9 @@ public void onIncomingMessage( }); } - private long calculateRequestedCount(final BlobSidecarsByRangeRequestMessage message) { - return specConfigDeneb.getMaxBlobsPerBlock() * message.getCount().longValue(); + private long calculateRequestedCount( + final BlobSidecarsByRangeRequestMessage message, final int maxBlobsPerBlock) { + return maxBlobsPerBlock * message.getCount().longValue(); } private boolean checkBlobSidecarsAreAvailable( @@ -234,6 +249,7 @@ class RequestState { private final UInt64 endSlot; private final UInt64 finalizedSlot; private final Map canonicalHotRoots; + private final int maxRequestBlobSidecars; private final AtomicInteger sentBlobSidecars = new AtomicInteger(0); @@ -247,12 +263,14 @@ class RequestState { final UInt64 startSlot, final UInt64 endSlot, final Map canonicalHotRoots, - final UInt64 finalizedSlot) { + final UInt64 finalizedSlot, + final int maxRequestBlobSidecars) { this.callback = callback; this.startSlot = startSlot; this.endSlot = endSlot; this.finalizedSlot = finalizedSlot; this.canonicalHotRoots = canonicalHotRoots; + this.maxRequestBlobSidecars = maxRequestBlobSidecars; } SafeFuture sendBlobSidecar(final BlobSidecar blobSidecar) { @@ -262,7 +280,7 @@ SafeFuture sendBlobSidecar(final BlobSidecar blobSidecar) { SafeFuture> loadNextBlobSidecar() { if (blobSidecarKeysIterator.isEmpty()) { return combinedChainDataClient - .getBlobSidecarKeys(startSlot, endSlot, specConfigDeneb.getMaxRequestBlobSidecars()) + .getBlobSidecarKeys(startSlot, endSlot, maxRequestBlobSidecars) .thenCompose( keys -> { blobSidecarKeysIterator = Optional.of(keys.iterator()); diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandler.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandler.java index 0ca9071724c..d19587974df 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandler.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandler.java @@ -34,7 +34,7 @@ import tech.pegasys.teku.networking.eth2.rpc.core.RpcException; import tech.pegasys.teku.networking.p2p.rpc.StreamClosedException; import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.SpecMilestone; 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; @@ -52,7 +52,6 @@ public class BlobSidecarsByRootMessageHandler private static final Logger LOG = LogManager.getLogger(); private final Spec spec; - private final SpecConfigDeneb specConfigDeneb; private final CombinedChainDataClient combinedChainDataClient; private final LabelledMetric requestCounter; @@ -60,11 +59,9 @@ public class BlobSidecarsByRootMessageHandler public BlobSidecarsByRootMessageHandler( final Spec spec, - final SpecConfigDeneb specConfigDeneb, final MetricsSystem metricsSystem, final CombinedChainDataClient combinedChainDataClient) { this.spec = spec; - this.specConfigDeneb = specConfigDeneb; this.combinedChainDataClient = combinedChainDataClient; requestCounter = metricsSystem.createLabelledCounter( @@ -82,7 +79,7 @@ public BlobSidecarsByRootMessageHandler( @Override public Optional validateRequest( final String protocolId, final BlobSidecarsByRootRequestMessage request) { - final int maxRequestBlobSidecars = specConfigDeneb.getMaxRequestBlobSidecars(); + final int maxRequestBlobSidecars = getMaxRequestBlobSidecars(); if (request.size() > maxRequestBlobSidecars) { requestCounter.labels("count_too_big").inc(); return Optional.of( @@ -156,6 +153,13 @@ public void onIncomingMessage( }); } + private int getMaxRequestBlobSidecars() { + final UInt64 epoch = + combinedChainDataClient.getRecentChainData().getCurrentEpoch().orElse(UInt64.ZERO); + final SpecMilestone specMilestone = spec.getForkSchedule().getSpecMilestoneAtEpoch(epoch); + return spec.forMilestone(specMilestone).miscHelpers().getMaxRequestBlobSidecars(); + } + private UInt64 getFinalizedEpoch() { return combinedChainDataClient .getFinalizedBlock() diff --git a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandlerTest.java b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandlerTest.java index aba5df4010b..752ee33c16b 100644 --- a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandlerTest.java +++ b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRangeMessageHandlerTest.java @@ -34,10 +34,9 @@ import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; -import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.AssertionsForInterfaceTypes; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import org.mockito.ArgumentCaptor; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem; @@ -51,81 +50,81 @@ import tech.pegasys.teku.networking.eth2.rpc.core.encodings.RpcEncoding; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; +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.blocks.SignedBeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobSidecarsByRangeRequestMessage; import tech.pegasys.teku.spec.datastructures.util.SlotAndBlockRootAndBlobIndex; -import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; import tech.pegasys.teku.spec.util.DataStructureUtil; import tech.pegasys.teku.storage.client.CombinedChainDataClient; import tech.pegasys.teku.storage.store.UpdatableStore; +@TestSpecContext(milestone = {SpecMilestone.DENEB, SpecMilestone.ELECTRA}) public class BlobSidecarsByRangeMessageHandlerTest { private static final RequestApproval ZERO_OBJECTS_REQUEST_APPROVAL = new RequestApproval.RequestApprovalBuilder().timeSeconds(ZERO).objectsCount(0).build(); - private static final RpcEncoding RPC_ENCODING = RpcEncoding.createSszSnappyEncoding( TestSpecFactory.createDefault().getNetworkingConfig().getMaxChunkSize()); - private final UInt64 genesisTime = UInt64.valueOf(1982239L); - private final UInt64 denebForkEpoch = UInt64.valueOf(1); - - private final Spec spec = TestSpecFactory.createMinimalWithDenebForkEpoch(denebForkEpoch); - - private final SpecConfigDeneb specConfigDeneb = - SpecConfigDeneb.required(spec.forMilestone(SpecMilestone.DENEB).getConfig()); - - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); - - private final int maxBlobsPerBlock = specConfigDeneb.getMaxBlobsPerBlock(); - - private final int slotsPerEpoch = spec.getSlotsPerEpoch(ZERO); - - private final UInt64 startSlot = denebForkEpoch.increment().times(slotsPerEpoch); - - private final Bytes32 headBlockRoot = dataStructureUtil.randomBytes32(); - + private final UInt64 currentForkEpoch = UInt64.valueOf(1); private final UInt64 count = UInt64.valueOf(5); - private final StubMetricsSystem metricsSystem = new StubMetricsSystem(); - private final Eth2Peer peer = mock(Eth2Peer.class); - private final MiscHelpersDeneb miscHelpers = - spec.forMilestone(SpecMilestone.DENEB).miscHelpers().toVersionDeneb().orElseThrow(); - @SuppressWarnings("unchecked") private final ResponseCallback listener = mock(ResponseCallback.class); private final CombinedChainDataClient combinedChainDataClient = mock(CombinedChainDataClient.class); private final UpdatableStore store = mock(UpdatableStore.class); - private final String protocolId = BeaconChainMethodIds.getBlobSidecarsByRangeMethodId(1, RPC_ENCODING); - - private final BlobSidecarsByRangeMessageHandler handler = - new BlobSidecarsByRangeMessageHandler( - spec, specConfigDeneb, metricsSystem, combinedChainDataClient); private final Optional allowedObjectsRequest = Optional.of( new RequestApproval.RequestApprovalBuilder().objectsCount(100).timeSeconds(ZERO).build()); + private SpecMilestone specMilestone; + private Spec spec; + private BlobSidecarsByRangeMessageHandler handler; + private DataStructureUtil dataStructureUtil; + private int maxBlobsPerBlock; + private int slotsPerEpoch; + private UInt64 startSlot; + @BeforeEach - public void setUp() { + public void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) { + specMilestone = specContext.getSpecMilestone(); + 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); + maxBlobsPerBlock = spec.forMilestone(specMilestone).miscHelpers().getMaxBlobsPerBlock(); + slotsPerEpoch = spec.getSlotsPerEpoch(ZERO); + startSlot = currentForkEpoch.increment().times(slotsPerEpoch); + handler = new BlobSidecarsByRangeMessageHandler(spec, metricsSystem, combinedChainDataClient); + when(peer.approveRequest()).thenReturn(true); when(peer.approveBlobSidecarsRequest(eq(listener), anyLong())) .thenReturn(allowedObjectsRequest); when(combinedChainDataClient.getEarliestAvailableBlobSidecarSlot()) .thenReturn(SafeFuture.completedFuture(Optional.of(ZERO))); when(combinedChainDataClient.getStore()).thenReturn(store); - when(combinedChainDataClient.getBestBlockRoot()).thenReturn(Optional.of(headBlockRoot)); + when(combinedChainDataClient.getBestBlockRoot()) + .thenReturn(Optional.of(dataStructureUtil.randomBytes32())); // everything is finalized by default when(combinedChainDataClient.getFinalizedBlockSlot()) .thenReturn(Optional.of(startSlot.plus(count))); @@ -133,10 +132,10 @@ public void setUp() { // mock store when(store.getGenesisTime()).thenReturn(genesisTime); - setCurrentEpoch(denebForkEpoch.increment()); + setCurrentEpoch(currentForkEpoch.increment()); } - @Test + @TestTemplate public void validateRequest_validRequest() { final Optional result = handler.validateRequest( @@ -144,10 +143,10 @@ public void validateRequest_validRequest() { assertThat(result).isEmpty(); } - @Test + @TestTemplate public void validateRequest_shouldRejectRequestWhenCountIsTooBig() { final UInt64 maxRequestBlobSidecars = - UInt64.valueOf(specConfigDeneb.getMaxRequestBlobSidecars()); + UInt64.valueOf(spec.forMilestone(specMilestone).miscHelpers().getMaxRequestBlobSidecars()); final BlobSidecarsByRangeRequestMessage request = new BlobSidecarsByRangeRequestMessage( startSlot, maxRequestBlobSidecars.increment(), maxBlobsPerBlock); @@ -170,7 +169,7 @@ public void validateRequest_shouldRejectRequestWhenCountIsTooBig() { assertThat(rateLimitedCount).isOne(); } - @Test + @TestTemplate public void shouldNotSendBlobSidecarsIfPeerIsRateLimited() { when(peer.approveBlobSidecarsRequest(listener, count.times(maxBlobsPerBlock).longValue())) @@ -197,7 +196,7 @@ public void shouldNotSendBlobSidecarsIfPeerIsRateLimited() { verifyNoInteractions(listener); } - @Test + @TestTemplate public void shouldSendResourceUnavailableIfBlobSidecarsAreNotAvailable() { // current epoch is 5020 @@ -207,7 +206,7 @@ public void shouldSendResourceUnavailableIfBlobSidecarsAreNotAvailable() { when(combinedChainDataClient.getEarliestAvailableBlobSidecarSlot()) .thenReturn( SafeFuture.completedFuture( - Optional.of(denebForkEpoch.plus(5009).times(slotsPerEpoch)))); + Optional.of(currentForkEpoch.plus(5009).times(slotsPerEpoch)))); // start slot in epoch 5000 within MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS range final BlobSidecarsByRangeRequestMessage request = @@ -231,12 +230,13 @@ public void shouldSendResourceUnavailableIfBlobSidecarsAreNotAvailable() { "Requested blob sidecars are not available.")); } - @Test + @TestTemplate public void shouldCompleteSuccessfullyIfNoBlobSidecarsInRange() { when(combinedChainDataClient.getBlobSidecarKeys(any(), any(), anyLong())) .thenReturn(SafeFuture.completedFuture(Collections.emptyList())); final BlobSidecarsByRangeRequestMessage request = - new BlobSidecarsByRangeRequestMessage(ZERO, count, maxBlobsPerBlock); + new BlobSidecarsByRangeRequestMessage( + currentForkEpoch.plus(1).times(slotsPerEpoch), count, maxBlobsPerBlock); handler.onIncomingMessage(protocolId, peer, request, listener); @@ -254,7 +254,7 @@ public void shouldCompleteSuccessfullyIfNoBlobSidecarsInRange() { verify(listener).completeSuccessfully(); } - @Test + @TestTemplate public void shouldSendToPeerRequestedNumberOfFinalizedBlobSidecars() { final BlobSidecarsByRangeRequestMessage request = @@ -283,7 +283,7 @@ public void shouldSendToPeerRequestedNumberOfFinalizedBlobSidecars() { AssertionsForInterfaceTypes.assertThat(actualSent).containsExactlyElementsOf(expectedSent); } - @Test + @TestTemplate public void shouldSendToPeerRequestedNumberOfCanonicalBlobSidecars() { final UInt64 latestFinalizedSlot = startSlot.plus(count).minus(3); @@ -341,7 +341,7 @@ public void shouldSendToPeerRequestedNumberOfCanonicalBlobSidecars() { AssertionsForInterfaceTypes.assertThat(actualSent).containsExactlyElementsOf(expectedSent); } - @Test + @TestTemplate public void shouldIgnoreRequestWhenCountIsZero() { final BlobSidecarsByRangeRequestMessage request = @@ -367,7 +367,7 @@ public void shouldIgnoreRequestWhenCountIsZero() { AssertionsForInterfaceTypes.assertThat(actualSent).isEmpty(); } - @Test + @TestTemplate public void shouldIgnoreRequestWhenCountIsZeroAndHotSlotRequested() { // not finalized final UInt64 hotStartSlot = startSlot.plus(7); @@ -430,7 +430,10 @@ private List> setupK UInt64.rangeClosed( ZERO, dataStructureUtil - .randomUInt64(miscHelpers.getBlobKzgCommitmentsCount(block)) + .randomUInt64( + spec.forMilestone(specMilestone) + .miscHelpers() + .getBlobKzgCommitmentsCount(block)) .minusMinZero(1)) .forEach( index -> diff --git a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandlerTest.java b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandlerTest.java index 8ab1801777e..0369973730a 100644 --- a/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandlerTest.java +++ b/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/BlobSidecarsByRootMessageHandlerTest.java @@ -32,7 +32,7 @@ import java.util.stream.IntStream; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import org.mockito.ArgumentCaptor; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem; @@ -46,66 +46,82 @@ import tech.pegasys.teku.networking.eth2.rpc.core.encodings.RpcEncoding; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.TestSpecContext; import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.TestSpecInvocationContextProvider; import tech.pegasys.teku.spec.config.SpecConfigDeneb; 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.datastructures.networking.libp2p.rpc.BlobSidecarsByRootRequestMessage; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobSidecarsByRootRequestMessageSchema; -import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; import tech.pegasys.teku.spec.util.DataStructureUtil; import tech.pegasys.teku.storage.client.CombinedChainDataClient; +import tech.pegasys.teku.storage.client.RecentChainData; import tech.pegasys.teku.storage.store.UpdatableStore; +@TestSpecContext(milestone = {SpecMilestone.DENEB, SpecMilestone.ELECTRA}) public class BlobSidecarsByRootMessageHandlerTest { private final UInt64 genesisTime = UInt64.valueOf(1982239L); - private final UInt64 denebForkEpoch = UInt64.valueOf(1); - - private final Spec spec = TestSpecFactory.createMinimalWithDenebForkEpoch(denebForkEpoch); - private final SpecConfigDeneb specConfigDeneb = - SpecConfigDeneb.required(spec.forMilestone(SpecMilestone.DENEB).getConfig()); - private final int maxChunkSize = spec.getNetworkingConfig().getMaxChunkSize(); - private final BlobSidecarsByRootRequestMessageSchema messageSchema = - SchemaDefinitionsDeneb.required(spec.forMilestone(SpecMilestone.DENEB).getSchemaDefinitions()) - .getBlobSidecarsByRootRequestMessageSchema(); - private final RpcEncoding rpcEncoding = RpcEncoding.createSszSnappyEncoding(maxChunkSize); - - private final String protocolId = - BeaconChainMethodIds.getBlobSidecarsByRootMethodId(1, rpcEncoding); - - private final UInt64 denebFirstSlot = spec.computeStartSlotAtEpoch(denebForkEpoch); - - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); - + private final UInt64 currentForkEpoch = UInt64.valueOf(1); + private BlobSidecarsByRootRequestMessageSchema messageSchema; private final ArgumentCaptor blobSidecarCaptor = ArgumentCaptor.forClass(BlobSidecar.class); - private final ArgumentCaptor rpcExceptionCaptor = ArgumentCaptor.forClass(RpcException.class); + private final Optional allowedObjectsRequest = + Optional.of( + new RequestApproval.RequestApprovalBuilder().objectsCount(100).timeSeconds(ZERO).build()); @SuppressWarnings("unchecked") private final ResponseCallback callback = mock(ResponseCallback.class); private final CombinedChainDataClient combinedChainDataClient = mock(CombinedChainDataClient.class); + private final RecentChainData recentChainData = mock(RecentChainData.class); private final UpdatableStore store = mock(UpdatableStore.class); - private final Eth2Peer peer = mock(Eth2Peer.class); - private final StubMetricsSystem metricsSystem = new StubMetricsSystem(); - - private final BlobSidecarsByRootMessageHandler handler = - new BlobSidecarsByRootMessageHandler( - spec, specConfigDeneb, metricsSystem, combinedChainDataClient); - - private final Optional allowedObjectsRequest = - Optional.of( - new RequestApproval.RequestApprovalBuilder().objectsCount(100).timeSeconds(ZERO).build()); + private String protocolId; + private UInt64 currentForkFirstSlot; + private DataStructureUtil dataStructureUtil; + private BlobSidecarsByRootMessageHandler handler; + private SpecMilestone specMilestone; + private Spec spec; @BeforeEach - public void setup() { + public void setup(final TestSpecInvocationContextProvider.SpecContext specContext) { + specMilestone = specContext.getSpecMilestone(); + 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); + messageSchema = + specMilestone.equals(SpecMilestone.DENEB) + ? spec.atEpoch(currentForkEpoch) + .getSchemaDefinitions() + .toVersionDeneb() + .orElseThrow() + .getBlobSidecarsByRootRequestMessageSchema() + : spec.atEpoch(currentForkEpoch) + .getSchemaDefinitions() + .toVersionElectra() + .orElseThrow() + .getBlobSidecarsByRootRequestMessageSchema(); + currentForkFirstSlot = spec.computeStartSlotAtEpoch(currentForkEpoch); + final int maxChunkSize = spec.getNetworkingConfig().getMaxChunkSize(); + final RpcEncoding rpcEncoding = RpcEncoding.createSszSnappyEncoding(maxChunkSize); + protocolId = BeaconChainMethodIds.getBlobSidecarsByRootMethodId(1, rpcEncoding); + handler = new BlobSidecarsByRootMessageHandler(spec, metricsSystem, combinedChainDataClient); + when(peer.approveRequest()).thenReturn(true); when(peer.approveBlobSidecarsRequest(eq(callback), anyLong())) .thenReturn(allowedObjectsRequest); @@ -113,11 +129,12 @@ public void setup() { when(combinedChainDataClient.getBlockByBlockRoot(any())) .thenReturn( SafeFuture.completedFuture( - Optional.of(dataStructureUtil.randomSignedBeaconBlock(denebFirstSlot)))); + Optional.of(dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot)))); // deneb fork epoch is finalized when(combinedChainDataClient.getFinalizedBlock()) - .thenReturn(Optional.of(dataStructureUtil.randomSignedBeaconBlock(denebFirstSlot))); + .thenReturn(Optional.of(dataStructureUtil.randomSignedBeaconBlock(currentForkFirstSlot))); when(combinedChainDataClient.getStore()).thenReturn(store); + when(combinedChainDataClient.getRecentChainData()).thenReturn(recentChainData); when(callback.respond(any())).thenReturn(SafeFuture.COMPLETE); // mock store @@ -126,12 +143,15 @@ public void setup() { when(store.getTimeSeconds()) .thenReturn( spec.getSlotStartTime( - denebForkEpoch.increment().times(spec.getSlotsPerEpoch(ZERO)), genesisTime)); + currentForkEpoch.increment().times(spec.getSlotsPerEpoch(ZERO)), genesisTime)); } - @Test + @TestTemplate public void validateRequest_shouldNotAllowRequestLargerThanMaximumAllowed() { - final int maxRequestBlobSidecars = specConfigDeneb.getMaxRequestBlobSidecars(); + final int maxRequestBlobSidecars = + spec.forMilestone(specMilestone).miscHelpers().getMaxRequestBlobSidecars(); + when(recentChainData.getCurrentEpoch()) + .thenReturn(Optional.of(dataStructureUtil.randomEpoch())); final BlobSidecarsByRootRequestMessage request = new BlobSidecarsByRootRequestMessage( messageSchema, dataStructureUtil.randomBlobIdentifiers(maxRequestBlobSidecars + 1)); @@ -156,7 +176,7 @@ public void validateRequest_shouldNotAllowRequestLargerThanMaximumAllowed() { assertThat(countTooBigCount).isOne(); } - @Test + @TestTemplate public void shouldNotSendBlobSidecarsIfPeerIsRateLimited() { when(peer.approveBlobSidecarsRequest(callback, 5)).thenReturn(Optional.empty()); @@ -182,7 +202,7 @@ public void shouldNotSendBlobSidecarsIfPeerIsRateLimited() { verifyNoInteractions(callback); } - @Test + @TestTemplate public void shouldSendAvailableOnlyResources() { final List blobIdentifiers = prepareBlobIdentifiers(4); @@ -223,7 +243,7 @@ public void shouldSendAvailableOnlyResources() { .containsExactlyInAnyOrderElementsOf(blobIdentifiersBlockRoots); } - @Test + @TestTemplate public void shouldSendResourceUnavailableIfBlockRootReferencesBlockEarlierThanTheMinimumRequestEpoch() { final List blobIdentifiers = prepareBlobIdentifiers(3); @@ -264,7 +284,7 @@ public void shouldSendAvailableOnlyResources() { blobIdentifiers.get(0).getBlockRoot()); } - @Test + @TestTemplate public void shouldSendResourceUnavailableIfBlobSidecarBlockRootReferencesBlockEarlierThanTheMinimumRequestEpoch() { final List blobIdentifiers = prepareBlobIdentifiers(3); @@ -301,7 +321,7 @@ public void shouldSendAvailableOnlyResources() { blobIdentifiers.get(0).getBlockRoot()); } - @Test + @TestTemplate public void shouldSendToPeerRequestedBlobSidecars() { final List blobIdentifiers = prepareBlobIdentifiers(5); From f14776b8ba355cb0f0ea6353268fb8714c911491 Mon Sep 17 00:00:00 2001 From: Mehdi AOUADI Date: Tue, 5 Nov 2024 16:35:15 +0100 Subject: [PATCH 2/2] update tests --- .../BlobSidecarsByRangeIntegrationTest.java | 39 +++-- .../BlobSidecarsByRootIntegrationTest.java | 39 +++-- ...arsByRangeListenerValidatingProxyTest.java | 143 +++++++++++------- ...carsByRootListenerValidatingProxyTest.java | 73 ++++++--- .../BlobSidecarsByRootValidatorTest.java | 106 +++++++------ 5 files changed, 259 insertions(+), 141 deletions(-) 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()); + } }