From 5a909c9a45ca4ccee94aaff79c7d376b74aa90ae Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Thu, 13 Jun 2024 10:47:51 +0100 Subject: [PATCH 1/3] Dump blob sidecars which failed data availability --- CHANGELOG.md | 2 + .../forkchoice/ForkChoice.java | 18 ++++++--- .../statetransition/util/DebugDataDumper.java | 11 ++++++ .../util/DebugDataFileDumper.java | 37 ++++++++++++++++++- .../forkchoice/ForkChoiceTest.java | 7 ++++ .../util/DebugDataFileDumperTest.java | 25 ++++++++++++- 6 files changed, 92 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c017d9e20..9393a261a8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ the [releases page](https://github.com/Consensys/teku/releases). ### Breaking Changes +- Renamed `--Xp2p-dumps-to-file-enabled` hidden CLI option to `--Xdebug-data-dumping-enabled` + ### Additions and Improvements - Added metadata fields to `/eth/v1/beacon/blob_sidecars/{block_id}` Beacon API response as per https://github.com/ethereum/beacon-APIs/pull/441 diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java index ccf50d754dd..e2c4251a444 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java @@ -17,6 +17,8 @@ import static tech.pegasys.teku.infrastructure.logging.P2PLogger.P2P_LOG; import static tech.pegasys.teku.infrastructure.time.TimeUtilities.secondsToMillis; import static tech.pegasys.teku.spec.constants.NetworkConstants.INTERVALS_PER_SLOT; +import static tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult.INVALID; +import static tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult.NOT_AVAILABLE; import static tech.pegasys.teku.statetransition.forkchoice.StateRootCollector.addParentStateRoots; import com.google.common.annotations.VisibleForTesting; @@ -540,18 +542,22 @@ private BlockImportResult importBlockAndState( payloadResult.getFailureCause().orElseThrow()); } + LOG.debug("blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString); + switch (blobSidecarsAndValidationResult.getValidationResult()) { - case VALID, NOT_REQUIRED -> LOG.debug( - "blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString); case NOT_AVAILABLE -> { - LOG.debug( - "blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString); + debugDataDumper.saveFailedDataAvailabilityBlobSidecars( + blobSidecarsAndValidationResult.getBlobSidecars(), + NOT_AVAILABLE.toString(), + blobSidecarsAndValidationResult.getCause()); return BlockImportResult.failedDataAvailabilityCheckNotAvailable( blobSidecarsAndValidationResult.getCause()); } case INVALID -> { - LOG.error( - "blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString); + debugDataDumper.saveFailedDataAvailabilityBlobSidecars( + blobSidecarsAndValidationResult.getBlobSidecars(), + INVALID.toString(), + blobSidecarsAndValidationResult.getCause()); return BlockImportResult.failedDataAvailabilityCheckInvalid( blobSidecarsAndValidationResult.getCause()); } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java index aebd1fc32e2..3d2e90be4e5 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java @@ -13,10 +13,12 @@ package tech.pegasys.teku.statetransition.util; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; public interface DebugDataDumper { @@ -42,6 +44,12 @@ public void saveInvalidBlock( final SignedBeaconBlock block, final String failureReason, final Optional failureCause) {} + + @Override + public void saveFailedDataAvailabilityBlobSidecars( + final List blobSidecars, + final String failureReason, + final Optional failureCause) {} }; void saveGossipMessageDecodingError( @@ -58,4 +66,7 @@ void saveGossipRejectedMessage( void saveInvalidBlock( SignedBeaconBlock block, String failureReason, Optional failureCause); + + void saveFailedDataAvailabilityBlobSidecars( + List blobSidecars, String failureReason, Optional failureCause); } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java index a5b93ca645c..a92bd104950 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java @@ -23,6 +23,7 @@ import java.sql.Date; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; import org.apache.logging.log4j.LogManager; @@ -31,6 +32,7 @@ import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.infrastructure.time.TimeProvider; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; public class DebugDataFileDumper implements DebugDataDumper { @@ -41,6 +43,8 @@ public class DebugDataFileDumper implements DebugDataDumper { private static final String DECODING_ERROR_SUB_DIR = "decoding_error"; private static final String REJECTED_SUB_DIR = "rejected"; private static final String INVALID_BLOCK_DIR = "invalid_blocks"; + private static final String FAILED_DATA_AVAILABILITY_BLOB_SIDECARS_DIR = + "failed_data_availability_blob_sidecars"; private boolean enabled; private final Path directory; @@ -125,7 +129,7 @@ public void saveInvalidBlock( "invalid block", Path.of(INVALID_BLOCK_DIR).resolve(fileName), block.sszSerialize()); if (success) { LOG.warn( - "Rejecting invalid block at slot {} with root {} because {}", + "Rejecting invalid block at slot {} with root {}, reason: {}, cause: {}", slot, blockRoot, failureReason, @@ -133,6 +137,37 @@ public void saveInvalidBlock( } } + @Override + public void saveFailedDataAvailabilityBlobSidecars( + final List blobSidecars, + final String failureReason, + final Optional failureCause) { + if (!enabled) { + return; + } + blobSidecars.forEach( + blobSidecar -> { + final UInt64 slot = blobSidecar.getSlot(); + final Bytes32 blockRoot = blobSidecar.getBlockRoot(); + final UInt64 index = blobSidecar.getIndex(); + final String fileName = + String.format("%s_%s_%s.ssz", slot, blockRoot.toUnprefixedHexString(), index); + final boolean success = + saveBytesToFile( + "failed data availability blob sidecar", + Path.of(FAILED_DATA_AVAILABILITY_BLOB_SIDECARS_DIR).resolve(fileName), + blobSidecar.sszSerialize()); + if (success) { + LOG.warn( + "Blob sidecar at slot {} with block root {} has failed the data availability check, reason: {}, cause: {}", + slot, + blockRoot, + failureReason, + failureCause.orElse(null)); + } + }); + } + @VisibleForTesting boolean saveBytesToFile( final String description, final Path relativeFilePath, final Bytes bytes) { diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java index 1098ad72f81..3f22a4be697 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java @@ -91,6 +91,7 @@ import tech.pegasys.teku.spec.logic.common.statetransition.results.BlockImportResult.FailureReason; import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsAndValidationResult; import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsAvailabilityChecker; +import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult; import tech.pegasys.teku.spec.util.DataStructureUtil; import tech.pegasys.teku.statetransition.blobs.BlobSidecarManager; import tech.pegasys.teku.statetransition.forkchoice.ForkChoice.OptimisticHeadSubscriber; @@ -245,6 +246,9 @@ void onBlock_shouldFailIfBlobsAreNotAvailable() { verify(blobSidecarManager).createAvailabilityChecker(blockAndState.getBlock()); verify(blobSidecarsAvailabilityChecker).initiateDataAvailabilityCheck(); verify(blobSidecarsAvailabilityChecker).getAvailabilityCheckResult(); + verify(debugDataDumper) + .saveFailedDataAvailabilityBlobSidecars( + any(), eq(BlobSidecarsValidationResult.NOT_AVAILABLE.toString()), eq(Optional.empty())); } @Test @@ -264,6 +268,9 @@ void onBlock_consensusValidationShouldNotResolveWhenDataAvailabilityFails() { verify(blobSidecarManager).createAvailabilityChecker(blockAndState.getBlock()); verify(blobSidecarsAvailabilityChecker).initiateDataAvailabilityCheck(); verify(blobSidecarsAvailabilityChecker).getAvailabilityCheckResult(); + verify(debugDataDumper) + .saveFailedDataAvailabilityBlobSidecars( + any(), eq(BlobSidecarsValidationResult.NOT_AVAILABLE.toString()), eq(Optional.empty())); } @Test diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java index 1cd40a66f8d..2da2c9c38f1 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java @@ -24,6 +24,7 @@ import java.sql.Date; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; @@ -33,12 +34,13 @@ import tech.pegasys.teku.infrastructure.time.StubTimeProvider; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.TestSpecFactory; +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; class DebugDataFileDumperTest { final DataStructureUtil dataStructureUtil = - new DataStructureUtil(TestSpecFactory.createDefault()); + new DataStructureUtil(TestSpecFactory.createMinimalDeneb()); private final StubTimeProvider timeProvider = StubTimeProvider.withTimeInSeconds(10_000); @Test @@ -91,6 +93,27 @@ void saveInvalidBlockToFile_shouldSaveToFile(@TempDir final Path tempDir) { checkBytesSavedToFile(expectedFile, block.sszSerialize()); } + @Test + void saveFailedDataAvailabilityBlobSidecars_shouldSaveToFiles(@TempDir final Path tempDir) { + final DebugDataFileDumper dumper = new DebugDataFileDumper(tempDir); + final List blobSidecars = dataStructureUtil.randomBlobSidecars(3); + dumper.saveFailedDataAvailabilityBlobSidecars( + blobSidecars, "reason", Optional.of(new Throwable())); + + blobSidecars.forEach( + blobSidecar -> { + final String fileName = + String.format( + "%s_%s_%s.ssz", + blobSidecar.getSlot(), + blobSidecar.getBlockRoot().toUnprefixedHexString(), + blobSidecar.getIndex()); + final Path expectedFile = + tempDir.resolve("failed_data_availability_blob_sidecars").resolve(fileName); + checkBytesSavedToFile(expectedFile, blobSidecar.sszSerialize()); + }); + } + @Test void saveBytesToFile_shouldNotThrowExceptionWhenNoDirectory(@TempDir final Path tempDir) { final DebugDataFileDumper dumper = new DebugDataFileDumper(tempDir); From ed3147d46b51c834daa0ff90e9ef6dc3e50c057b Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Thu, 13 Jun 2024 10:55:32 +0100 Subject: [PATCH 2/3] add default case --- .../tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java index e2c4251a444..07f882bac4d 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java @@ -561,6 +561,7 @@ private BlockImportResult importBlockAndState( return BlockImportResult.failedDataAvailabilityCheckInvalid( blobSidecarsAndValidationResult.getCause()); } + default -> {} } final ForkChoiceStrategy forkChoiceStrategy = getForkChoiceStrategy(); From 80e684e18568544e43e7a91011501f8d1eae9234 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Thu, 13 Jun 2024 14:00:38 +0100 Subject: [PATCH 3/3] changes --- .../forkchoice/ForkChoice.java | 11 ++----- .../statetransition/util/DebugDataDumper.java | 9 ++--- .../util/DebugDataFileDumper.java | 33 ++++++++----------- .../forkchoice/ForkChoiceTest.java | 32 ++++++++++++++---- .../util/DebugDataFileDumperTest.java | 20 +++++++---- 5 files changed, 58 insertions(+), 47 deletions(-) diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java index 07f882bac4d..601d05a0f36 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java @@ -18,7 +18,6 @@ import static tech.pegasys.teku.infrastructure.time.TimeUtilities.secondsToMillis; import static tech.pegasys.teku.spec.constants.NetworkConstants.INTERVALS_PER_SLOT; import static tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult.INVALID; -import static tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult.NOT_AVAILABLE; import static tech.pegasys.teku.statetransition.forkchoice.StateRootCollector.addParentStateRoots; import com.google.common.annotations.VisibleForTesting; @@ -546,18 +545,12 @@ private BlockImportResult importBlockAndState( switch (blobSidecarsAndValidationResult.getValidationResult()) { case NOT_AVAILABLE -> { - debugDataDumper.saveFailedDataAvailabilityBlobSidecars( - blobSidecarsAndValidationResult.getBlobSidecars(), - NOT_AVAILABLE.toString(), - blobSidecarsAndValidationResult.getCause()); return BlockImportResult.failedDataAvailabilityCheckNotAvailable( blobSidecarsAndValidationResult.getCause()); } case INVALID -> { - debugDataDumper.saveFailedDataAvailabilityBlobSidecars( - blobSidecarsAndValidationResult.getBlobSidecars(), - INVALID.toString(), - blobSidecarsAndValidationResult.getCause()); + debugDataDumper.saveInvalidBlobSidecars( + blobSidecarsAndValidationResult.getBlobSidecars(), block); return BlockImportResult.failedDataAvailabilityCheckInvalid( blobSidecarsAndValidationResult.getCause()); } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java index 3d2e90be4e5..e8af45dba06 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataDumper.java @@ -46,10 +46,8 @@ public void saveInvalidBlock( final Optional failureCause) {} @Override - public void saveFailedDataAvailabilityBlobSidecars( - final List blobSidecars, - final String failureReason, - final Optional failureCause) {} + public void saveInvalidBlobSidecars( + final List blobSidecars, final SignedBeaconBlock block) {} }; void saveGossipMessageDecodingError( @@ -67,6 +65,5 @@ void saveGossipRejectedMessage( void saveInvalidBlock( SignedBeaconBlock block, String failureReason, Optional failureCause); - void saveFailedDataAvailabilityBlobSidecars( - List blobSidecars, String failureReason, Optional failureCause); + void saveInvalidBlobSidecars(List blobSidecars, SignedBeaconBlock block); } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java index a92bd104950..ccdd1da1710 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumper.java @@ -43,8 +43,7 @@ public class DebugDataFileDumper implements DebugDataDumper { private static final String DECODING_ERROR_SUB_DIR = "decoding_error"; private static final String REJECTED_SUB_DIR = "rejected"; private static final String INVALID_BLOCK_DIR = "invalid_blocks"; - private static final String FAILED_DATA_AVAILABILITY_BLOB_SIDECARS_DIR = - "failed_data_availability_blob_sidecars"; + private static final String INVALID_BLOB_SIDECARS_DIR = "invalid_blob_sidecars"; private boolean enabled; private final Path directory; @@ -138,13 +137,18 @@ public void saveInvalidBlock( } @Override - public void saveFailedDataAvailabilityBlobSidecars( - final List blobSidecars, - final String failureReason, - final Optional failureCause) { + public void saveInvalidBlobSidecars( + final List blobSidecars, final SignedBeaconBlock block) { if (!enabled) { return; } + final String kzgCommitmentsFileName = + String.format( + "%s_%s_kzg_commitments.ssz", block.getSlot(), block.getRoot().toUnprefixedHexString()); + saveBytesToFile( + "kzg commitments", + Path.of(INVALID_BLOB_SIDECARS_DIR).resolve(kzgCommitmentsFileName), + block.getMessage().getBody().getOptionalBlobKzgCommitments().orElseThrow().sszSerialize()); blobSidecars.forEach( blobSidecar -> { final UInt64 slot = blobSidecar.getSlot(); @@ -152,19 +156,10 @@ public void saveFailedDataAvailabilityBlobSidecars( final UInt64 index = blobSidecar.getIndex(); final String fileName = String.format("%s_%s_%s.ssz", slot, blockRoot.toUnprefixedHexString(), index); - final boolean success = - saveBytesToFile( - "failed data availability blob sidecar", - Path.of(FAILED_DATA_AVAILABILITY_BLOB_SIDECARS_DIR).resolve(fileName), - blobSidecar.sszSerialize()); - if (success) { - LOG.warn( - "Blob sidecar at slot {} with block root {} has failed the data availability check, reason: {}, cause: {}", - slot, - blockRoot, - failureReason, - failureCause.orElse(null)); - } + saveBytesToFile( + "blob sidecar", + Path.of(INVALID_BLOB_SIDECARS_DIR).resolve(fileName), + blobSidecar.sszSerialize()); }); } diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java index 3f22a4be697..70d9ca7e103 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java @@ -91,7 +91,6 @@ import tech.pegasys.teku.spec.logic.common.statetransition.results.BlockImportResult.FailureReason; import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsAndValidationResult; import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsAvailabilityChecker; -import tech.pegasys.teku.spec.logic.versions.deneb.blobs.BlobSidecarsValidationResult; import tech.pegasys.teku.spec.util.DataStructureUtil; import tech.pegasys.teku.statetransition.blobs.BlobSidecarManager; import tech.pegasys.teku.statetransition.forkchoice.ForkChoice.OptimisticHeadSubscriber; @@ -246,9 +245,31 @@ void onBlock_shouldFailIfBlobsAreNotAvailable() { verify(blobSidecarManager).createAvailabilityChecker(blockAndState.getBlock()); verify(blobSidecarsAvailabilityChecker).initiateDataAvailabilityCheck(); verify(blobSidecarsAvailabilityChecker).getAvailabilityCheckResult(); - verify(debugDataDumper) - .saveFailedDataAvailabilityBlobSidecars( - any(), eq(BlobSidecarsValidationResult.NOT_AVAILABLE.toString()), eq(Optional.empty())); + } + + @Test + void onBlock_shouldFailIfBlobsAreInvalid() { + setupWithSpec(TestSpecFactory.createMinimalDeneb()); + final SignedBlockAndState blockAndState = chainBuilder.generateBlockAtSlot(ONE); + storageSystem.chainUpdater().advanceCurrentSlotToAtLeast(blockAndState.getSlot()); + final List blobSidecars = + storageSystem + .chainStorage() + .getBlobSidecarsBySlotAndBlockRoot(blockAndState.getSlotAndBlockRoot()) + .join(); + + when(blobSidecarsAvailabilityChecker.getAvailabilityCheckResult()) + .thenReturn( + SafeFuture.completedFuture( + BlobSidecarsAndValidationResult.invalidResult(blobSidecars))); + + importBlockAndAssertFailure( + blockAndState, FailureReason.FAILED_DATA_AVAILABILITY_CHECK_INVALID); + + verify(blobSidecarManager).createAvailabilityChecker(blockAndState.getBlock()); + verify(blobSidecarsAvailabilityChecker).initiateDataAvailabilityCheck(); + verify(blobSidecarsAvailabilityChecker).getAvailabilityCheckResult(); + verify(debugDataDumper).saveInvalidBlobSidecars(blobSidecars, blockAndState.getBlock()); } @Test @@ -268,9 +289,6 @@ void onBlock_consensusValidationShouldNotResolveWhenDataAvailabilityFails() { verify(blobSidecarManager).createAvailabilityChecker(blockAndState.getBlock()); verify(blobSidecarsAvailabilityChecker).initiateDataAvailabilityCheck(); verify(blobSidecarsAvailabilityChecker).getAvailabilityCheckResult(); - verify(debugDataDumper) - .saveFailedDataAvailabilityBlobSidecars( - any(), eq(BlobSidecarsValidationResult.NOT_AVAILABLE.toString()), eq(Optional.empty())); } @Test diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java index 2da2c9c38f1..04b5510af69 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/DebugDataFileDumperTest.java @@ -94,11 +94,20 @@ void saveInvalidBlockToFile_shouldSaveToFile(@TempDir final Path tempDir) { } @Test - void saveFailedDataAvailabilityBlobSidecars_shouldSaveToFiles(@TempDir final Path tempDir) { + void saveInvalidBlobSidecars_shouldSaveToFiles(@TempDir final Path tempDir) { final DebugDataFileDumper dumper = new DebugDataFileDumper(tempDir); - final List blobSidecars = dataStructureUtil.randomBlobSidecars(3); - dumper.saveFailedDataAvailabilityBlobSidecars( - blobSidecars, "reason", Optional.of(new Throwable())); + final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlock(); + final List blobSidecars = dataStructureUtil.randomBlobSidecarsForBlock(block); + dumper.saveInvalidBlobSidecars(blobSidecars, block); + + final String kzgCommitmentsFileName = + String.format( + "%s_%s_kzg_commitments.ssz", block.getSlot(), block.getRoot().toUnprefixedHexString()); + final Path expectedKzgCommitmentsFileName = + tempDir.resolve("invalid_blob_sidecars").resolve(kzgCommitmentsFileName); + checkBytesSavedToFile( + expectedKzgCommitmentsFileName, + block.getMessage().getBody().getOptionalBlobKzgCommitments().orElseThrow().sszSerialize()); blobSidecars.forEach( blobSidecar -> { @@ -108,8 +117,7 @@ void saveFailedDataAvailabilityBlobSidecars_shouldSaveToFiles(@TempDir final Pat blobSidecar.getSlot(), blobSidecar.getBlockRoot().toUnprefixedHexString(), blobSidecar.getIndex()); - final Path expectedFile = - tempDir.resolve("failed_data_availability_blob_sidecars").resolve(fileName); + final Path expectedFile = tempDir.resolve("invalid_blob_sidecars").resolve(fileName); checkBytesSavedToFile(expectedFile, blobSidecar.sszSerialize()); }); }