Stop adding bad proposed block to bad block manager (#5082)

* Add flag to distinguish when bad block is a proposed block

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add flag to distinguish when bad block is a proposed block

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* javadoc

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add shouldRecordBadBlock flag to stop adding proposed bad blocks to the bad block manager

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add overload to validateAndProcessBlock with shouldRecordBadBlock flag

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add unit test to ensure flag is being used to add blocks to bad block manager

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add unit test to ensure we don't add our own proposed bad block to the bad block manager

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add debug log when badBlock is not added

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Undo change done in the first approach

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Improve log

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Improve test names

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Improve javadoc of validateProposedBlock method

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Remove method from interface

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Change validateProposedBlock access modifier to private

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
This commit is contained in:
Gabriel Fukushima
2023-02-22 11:15:12 +11:00
committed by GitHub
parent 32583f467e
commit 66521cb3f2
5 changed files with 122 additions and 13 deletions

View File

@@ -270,7 +270,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
.createBlock(Optional.of(Collections.emptyList()), prevRandao, timestamp, withdrawals)
.getBlock();
BlockProcessingResult result = validateBlock(emptyBlock);
BlockProcessingResult result = validateProposedBlock(emptyBlock);
if (result.isSuccessful()) {
mergeContext.putPayloadById(
payloadIdentifier, new BlockWithReceipts(emptyBlock, result.getReceipts()));
@@ -401,7 +401,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
if (isBlockCreationCancelled(payloadIdentifier)) return;
final var resultBest = validateBlock(bestBlock);
final var resultBest = validateProposedBlock(bestBlock);
if (resultBest.isSuccessful()) {
if (isBlockCreationCancelled(payloadIdentifier)) return;
@@ -494,6 +494,22 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
return validationResult;
}
private BlockProcessingResult validateProposedBlock(final Block block) {
final var validationResult =
protocolSchedule
.getByBlockHeader(block.getHeader())
.getBlockValidator()
.validateAndProcessBlock(
protocolContext,
block,
HeaderValidationMode.FULL,
HeaderValidationMode.NONE,
false,
false);
return validationResult;
}
@Override
public BlockProcessingResult rememberBlock(final Block block) {
debugLambda(LOG, "Remember block {}", block::toLogString);

View File

@@ -317,6 +317,26 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
verify(willThrow, never()).addBadBlock(any(), any());
}
@Test
public void shouldNotRecordProposedBadBlockToBadBlockManager()
throws ExecutionException, InterruptedException {
// set up invalid parent to simulate one of the many conditions that can cause a block
// validation to fail
final BlockHeader invalidParentHeader = new BlockHeaderTestFixture().buildHeader();
blockCreationTask.get();
coordinator.preparePayload(
invalidParentHeader,
System.currentTimeMillis() / 1000,
Bytes32.ZERO,
suggestedFeeRecipient,
Optional.empty());
verify(badBlockManager, never()).addBadBlock(any(), any());
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
}
@Test
public void shouldContinueBuildingBlocksUntilFinalizeIsCalled()
throws InterruptedException, ExecutionException {

View File

@@ -35,6 +35,14 @@ public interface BlockValidator {
final HeaderValidationMode ommerValidationMode,
final boolean shouldPersist);
BlockProcessingResult validateAndProcessBlock(
final ProtocolContext context,
final Block block,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode,
final boolean shouldPersist,
final boolean shouldRecordBadBlock);
boolean fastBlockValidation(
final ProtocolContext context,
final Block block,

View File

@@ -71,7 +71,8 @@ public class MainnetBlockValidator implements BlockValidator {
final Block block,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode) {
return validateAndProcessBlock(context, block, headerValidationMode, ommerValidationMode, true);
return validateAndProcessBlock(
context, block, headerValidationMode, ommerValidationMode, true, true);
}
@Override
@@ -81,6 +82,18 @@ public class MainnetBlockValidator implements BlockValidator {
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode,
final boolean shouldPersist) {
return validateAndProcessBlock(
context, block, headerValidationMode, ommerValidationMode, shouldPersist, true);
}
@Override
public BlockProcessingResult validateAndProcessBlock(
final ProtocolContext context,
final Block block,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode,
final boolean shouldPersist,
final boolean shouldRecordBadBlock) {
final BlockHeader header = block.getHeader();
final BlockHeader parentHeader;
@@ -93,7 +106,7 @@ public class MainnetBlockValidator implements BlockValidator {
var retval =
new BlockProcessingResult(
"Parent block with hash " + header.getParentHash() + " not present");
handleAndLogImportFailure(block, retval);
handleAndLogImportFailure(block, retval, shouldRecordBadBlock);
return retval;
}
parentHeader = maybeParentHeader.get();
@@ -101,12 +114,12 @@ public class MainnetBlockValidator implements BlockValidator {
if (!blockHeaderValidator.validateHeader(
header, parentHeader, context, headerValidationMode)) {
var retval = new BlockProcessingResult("header validation rule violated, see logs");
handleAndLogImportFailure(block, retval);
handleAndLogImportFailure(block, retval, shouldRecordBadBlock);
return retval;
}
} catch (StorageException ex) {
var retval = new BlockProcessingResult(Optional.empty(), ex);
handleAndLogImportFailure(block, retval);
handleAndLogImportFailure(block, retval, shouldRecordBadBlock);
return retval;
}
@@ -129,19 +142,19 @@ public class MainnetBlockValidator implements BlockValidator {
"Unable to process block because parent world state "
+ parentHeader.getStateRoot()
+ " is not available");
handleAndLogImportFailure(block, retval);
handleAndLogImportFailure(block, retval, shouldRecordBadBlock);
return retval;
}
var result = processBlock(context, worldState, block);
if (result.isFailed()) {
handleAndLogImportFailure(block, result);
handleAndLogImportFailure(block, result, shouldRecordBadBlock);
return result;
} else {
List<TransactionReceipt> receipts =
result.getYield().map(BlockProcessingOutputs::getReceipts).orElse(new ArrayList<>());
if (!blockBodyValidator.validateBody(
context, block, receipts, worldState.rootHash(), ommerValidationMode)) {
handleAndLogImportFailure(block, result);
handleAndLogImportFailure(block, result, shouldRecordBadBlock);
return new BlockProcessingResult("failed to validate output of imported block");
}
if (result instanceof GoQuorumBlockProcessingResult) {
@@ -174,11 +187,13 @@ public class MainnetBlockValidator implements BlockValidator {
synchronizer -> synchronizer.healWorldState(ex.getMaybeAddress(), ex.getLocation()),
() ->
handleAndLogImportFailure(
block, new BlockProcessingResult(Optional.empty(), ex)));
block,
new BlockProcessingResult(Optional.empty(), ex),
shouldRecordBadBlock));
return new BlockProcessingResult(Optional.empty(), ex);
} catch (StorageException ex) {
var retval = new BlockProcessingResult(Optional.empty(), ex);
handleAndLogImportFailure(block, retval);
handleAndLogImportFailure(block, retval, shouldRecordBadBlock);
return retval;
} catch (Exception ex) {
throw new RuntimeException(ex);
@@ -186,7 +201,9 @@ public class MainnetBlockValidator implements BlockValidator {
}
private void handleAndLogImportFailure(
final Block invalidBlock, final BlockValidationResult result) {
final Block invalidBlock,
final BlockValidationResult result,
final boolean shouldRecordBadBlock) {
if (result.causedBy().isPresent()) {
LOG.info(
"Invalid block {}: {}, caused by {}",
@@ -201,7 +218,11 @@ public class MainnetBlockValidator implements BlockValidator {
LOG.info("Invalid block {}", invalidBlock.toLogString());
}
}
badBlockManager.addBadBlock(invalidBlock, result.causedBy());
if (shouldRecordBadBlock) {
badBlockManager.addBadBlock(invalidBlock, result.causedBy());
} else {
LOG.debug("Invalid block {} not added to badBlockManager ", invalidBlock.toLogString());
}
}
/**

View File

@@ -223,4 +223,48 @@ public class MainnetBlockValidatorTest {
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlock(badBlock.getHash())).containsSame(badBlock);
}
@Test
public void when_shouldRecordBadBlockIsFalse_Expect_BlockNotAddedToBadBlockManager() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY,
false,
false);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
}
@Test
public void when_shouldRecordBadBlockIsTrue_Expect_BlockAddedToBadBlockManager() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY,
false,
true);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void when_shouldRecordBadBlockIsNotSet_Expect_BlockAddedToBadBlockManager() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY,
false);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
}