Add debug_getBadBlocks method (#1378)

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
pull/1385/head
matkt 4 years ago committed by GitHub
parent 714f5fc56c
commit be89cd93f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 3
      ethereum/api/build.gradle
  3. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java
  4. 58
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlocks.java
  5. 45
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BadBlockResult.java
  6. 30
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java
  7. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java
  8. 137
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugGetBadBlockTest.java
  9. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java
  10. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java
  11. 49
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java
  12. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
  13. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java
  14. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  15. 240
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java
  16. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/VMReferenceTest.java
  17. 11
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java
  18. 8
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/CheckpointHeaderValidationStep.java
  19. 44
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java
  20. 49
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManagerTest.java
  21. 6
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java

@ -6,6 +6,7 @@
* The new version of the [web3js-eea library (v0.10)](https://github.com/PegaSysEng/web3js-eea) supports the onchain privacy group management changes made in Besu v1.5.3.
### Bug Fixes
* Added `debug_getBadBlocks` JSON-RPC API to analyze and detect consensus flaws. Even if a block is rejected it will be returned by this method [\#1378](https://github.com/hyperledger/besu/pull/1378)
* Fix logs queries missing results against chain head [\#1351](https://github.com/hyperledger/besu/pull/1351)
#### Previously identified known issues

@ -62,6 +62,9 @@ dependencies {
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.xerial.snappy:snappy-java'
annotationProcessor "org.immutables:value"
implementation "org.immutables:value-annotations"
runtimeOnly 'org.bouncycastle:bcpkix-jdk15on'
testImplementation project(':config')

@ -39,6 +39,7 @@ public enum RpcMethod {
DEBUG_TRACE_BLOCK_BY_NUMBER("debug_traceBlockByNumber"),
DEBUG_TRACE_TRANSACTION("debug_traceTransaction"),
DEBUG_BATCH_RAW_TRANSACTION("debug_batchSendRawTransaction"),
DEBUG_GET_BAD_BLOCKS("debug_getBadBlocks"),
PRIV_CALL("priv_call"),
PRIV_GET_PRIVATE_TRANSACTION("priv_getPrivateTransaction"),
PRIV_GET_TRANSACTION_COUNT("priv_getTransactionCount"),

@ -0,0 +1,58 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BadBlockResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.List;
import java.util.stream.Collectors;
public class DebugGetBadBlocks implements JsonRpcMethod {
private final BlockchainQueries blockchain;
private final ProtocolSchedule protocolSchedule;
private final BlockResultFactory blockResultFactory;
public DebugGetBadBlocks(
final BlockchainQueries blockchain,
final ProtocolSchedule protocolSchedule,
final BlockResultFactory blockResultFactory) {
this.blockchain = blockchain;
this.protocolSchedule = protocolSchedule;
this.blockResultFactory = blockResultFactory;
}
@Override
public String getName() {
return RpcMethod.DEBUG_GET_BAD_BLOCKS.getMethodName();
}
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final List<BadBlockResult> response =
protocolSchedule.getByBlockNumber(blockchain.headBlockNumber()).getBadBlocksManager()
.getBadBlocks().stream()
.map(block -> BadBlockResult.from(blockResultFactory.transactionComplete(block), block))
.collect(Collectors.toList());
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response);
}
}

@ -0,0 +1,45 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.ethereum.core.Block;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(allParameters = true)
@JsonSerialize(as = ImmutableBadBlockResult.class)
@JsonDeserialize(as = ImmutableBadBlockResult.class)
@JsonPropertyOrder({"block", "hash", "rlp"})
public interface BadBlockResult {
@JsonProperty("block")
BlockResult getBlockResult();
@JsonProperty("hash")
String getHash();
@JsonProperty("rlp")
String getRlp();
static BadBlockResult from(final BlockResult blockResult, final Block block) {
return ImmutableBadBlockResult.of(
blockResult, block.getHash().toHexString(), block.toRlp().toHexString());
}
}

@ -16,8 +16,11 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -52,6 +55,33 @@ public class BlockResultFactory {
includeCoinbase);
}
public BlockResult transactionComplete(final Block block) {
final int count = block.getBody().getTransactions().size();
final List<TransactionWithMetadata> transactionWithMetadata = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
transactionWithMetadata.add(
new TransactionWithMetadata(
block.getBody().getTransactions().get(i),
block.getHeader().getNumber(),
block.getHash(),
i));
}
final List<TransactionResult> txs =
transactionWithMetadata.stream()
.map(TransactionCompleteResult::new)
.collect(Collectors.toList());
final List<JsonNode> ommers =
block.getBody().getOmmers().stream()
.map(BlockHeader::getHash)
.map(Hash::toString)
.map(TextNode::new)
.collect(Collectors.toList());
return new BlockResult(
block.getHeader(), txs, ommers, block.getHeader().getDifficulty(), block.calculateSize());
}
public BlockResult transactionHash(final BlockWithMetadata<Hash, Hash> blockWithMetadata) {
return transactionHash(blockWithMetadata, false);
}

@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRange;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugBatchSendRawTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugGetBadBlocks;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugMetrics;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRangeAt;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock;
@ -28,6 +29,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@ -38,6 +40,8 @@ import java.util.Map;
public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final BlockResultFactory blockResult = new BlockResultFactory();
private final BlockchainQueries blockchainQueries;
private final ProtocolSchedule protocolSchedule;
private final ObservableMetricsSystem metricsSystem;
@ -78,6 +82,7 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
blockchainQueries),
new DebugTraceBlockByNumber(() -> new BlockTracer(blockReplay), blockchainQueries),
new DebugTraceBlockByHash(() -> new BlockTracer(blockReplay)),
new DebugBatchSendRawTransaction(transactionPool));
new DebugBatchSendRawTransaction(transactionPool),
new DebugGetBadBlocks(blockchainQueries, protocolSchedule, blockResult));
}
}

@ -0,0 +1,137 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BadBlockResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@SuppressWarnings("unchecked")
public class DebugGetBadBlockTest {
private final TransactionTestFixture transactionTestFixture = new TransactionTestFixture();
private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class);
private final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
private final BlockResultFactory blockResult = new BlockResultFactory();
private final BadBlockManager badBlockManager = new BadBlockManager();
private final DebugGetBadBlocks debugGetBadBlocks =
new DebugGetBadBlocks(blockchainQueries, protocolSchedule, blockResult);
@Test
public void nameShouldBeDebugTraceBlock() {
assertThat(debugGetBadBlocks.getName()).isEqualTo("debug_getBadBlocks");
}
@Test
public void shouldReturnCorrectResponse() {
final SECP256K1.KeyPair keyPair = SECP256K1.KeyPair.generate();
final List<Transaction> transactions = new ArrayList<>();
for (int i = 0; i < 3; i++) {
transactions.add(transactionTestFixture.createTransaction(keyPair));
}
final Block parentBlock =
new BlockDataGenerator()
.block(
BlockDataGenerator.BlockOptions.create()
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions()));
final Block badBlockWithTransaction =
new BlockDataGenerator()
.block(
BlockDataGenerator.BlockOptions.create()
.addTransaction(transactions)
.setBlockNumber(1)
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions())
.setParentHash(parentBlock.getHash()));
final Block badBlockWoTransaction =
new BlockDataGenerator()
.block(
BlockDataGenerator.BlockOptions.create()
.setBlockNumber(2)
.hasTransactions(false)
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions())
.setParentHash(parentBlock.getHash()));
badBlockManager.addBadBlock(badBlockWithTransaction);
badBlockManager.addBadBlock(badBlockWoTransaction);
final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
when(protocolSchedule.getByBlockNumber(anyLong())).thenReturn(protocolSpec);
when(protocolSpec.getBadBlocksManager()).thenReturn(badBlockManager);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlock", new Object[] {}));
final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) debugGetBadBlocks.response(request);
final Collection<BadBlockResult> result = (Collection<BadBlockResult>) response.getResult();
assertThat(result).hasSize(2);
for (BadBlockResult badBlockResult : result) {
if (badBlockResult.getBlockResult().getNumber().equals("0x1")) {
assertThat(badBlockResult.getBlockResult().getTransactions().size()).isEqualTo(3);
} else if (badBlockResult.getBlockResult().getNumber().equals("0x2")) {
assertThat(badBlockResult.getBlockResult().getTransactions()).isEmpty();
} else {
fail("Invalid response");
}
assertThat(badBlockResult.getRlp()).isNotEmpty();
assertThat(badBlockResult.getHash()).isNotEmpty();
assertThat(badBlockResult.getBlockResult().getNonce()).isNotEmpty();
}
}
@Test
public void shouldReturnCorrectResponseWhenNoInvalidBlockFound() {
final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
when(protocolSchedule.getByBlockNumber(anyLong())).thenReturn(protocolSpec);
when(protocolSpec.getBadBlocksManager()).thenReturn(badBlockManager);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlock", new Object[] {}));
final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) debugGetBadBlocks.response(request);
final Collection<BadBlockResult> result = (Collection<BadBlockResult>) response.getResult();
assertThat(result).hasSize(0);
}
}

@ -100,7 +100,8 @@ public class EthGetTransactionReceiptTest {
null,
TransactionPriceCalculator.frontier(),
Optional.empty(),
TransactionGasBudgetCalculator.frontier());
TransactionGasBudgetCalculator.frontier(),
null);
private final ProtocolSpec statusTransactionTypeSpec =
new ProtocolSpec(
"status",
@ -124,7 +125,8 @@ public class EthGetTransactionReceiptTest {
null,
TransactionPriceCalculator.frontier(),
Optional.empty(),
TransactionGasBudgetCalculator.frontier());
TransactionGasBudgetCalculator.frontier(),
null);
@SuppressWarnings("unchecked")
private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class);

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -41,13 +42,17 @@ public class MainnetBlockValidator implements BlockValidator {
private final BlockProcessor blockProcessor;
private final BadBlockManager badBlockManager;
public MainnetBlockValidator(
final BlockHeaderValidator blockHeaderValidator,
final BlockBodyValidator blockBodyValidator,
final BlockProcessor blockProcessor) {
final BlockProcessor blockProcessor,
final BadBlockManager badBlockManager) {
this.blockHeaderValidator = blockHeaderValidator;
this.blockBodyValidator = blockBodyValidator;
this.blockProcessor = blockProcessor;
this.badBlockManager = badBlockManager;
}
@Override
@ -66,11 +71,13 @@ public class MainnetBlockValidator implements BlockValidator {
header.getNumber(),
header.getHash(),
header.getParentHash());
badBlockManager.addBadBlock(block);
return Optional.empty();
}
final BlockHeader parentHeader = maybeParentHeader.get();
if (!blockHeaderValidator.validateHeader(header, parentHeader, context, headerValidationMode)) {
badBlockManager.addBadBlock(block);
return Optional.empty();
}
@ -82,17 +89,20 @@ public class MainnetBlockValidator implements BlockValidator {
"Unable to process block {} because parent world state {} is not available",
header.getNumber(),
parentHeader.getStateRoot());
badBlockManager.addBadBlock(block);
return Optional.empty();
}
final MutableWorldState worldState = maybeWorldState.get();
final BlockProcessor.Result result = blockProcessor.processBlock(blockchain, worldState, block);
if (!result.isSuccessful()) {
badBlockManager.addBadBlock(block);
return Optional.empty();
}
final List<TransactionReceipt> receipts = result.getReceipts();
if (!blockBodyValidator.validateBody(
context, block, receipts, worldState.rootHash(), ommerValidationMode)) {
badBlockManager.addBadBlock(block);
return Optional.empty();
}
@ -108,10 +118,12 @@ public class MainnetBlockValidator implements BlockValidator {
final HeaderValidationMode ommerValidationMode) {
final BlockHeader header = block.getHeader();
if (!blockHeaderValidator.validateHeader(header, context, headerValidationMode)) {
badBlockManager.addBadBlock(block);
return false;
}
if (!blockBodyValidator.validateBodyLight(context, block, receipts, ommerValidationMode)) {
badBlockManager.addBadBlock(block);
return false;
}
return true;

@ -0,0 +1,49 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.chain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Hash;
import java.util.Collection;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
public class BadBlockManager {
private final Cache<Hash, Block> badBlocks =
CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build();
/**
* Add a new invalid block.
*
* @param badBlock the invalid block
*/
public void addBadBlock(final Block badBlock) {
if (badBlock != null) {
this.badBlocks.put(badBlock.getHash(), badBlock);
}
}
/**
* Return all invalid blocks
*
* @return a collection of invalid blocks
*/
public Collection<Block> getBadBlocks() {
return badBlocks.asMap().values();
}
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.experimental.ExperimentalEIPs;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.fees.FeeMarket;
import org.hyperledger.besu.ethereum.core.fees.TransactionPriceCalculator;
@ -38,6 +39,7 @@ public class ProtocolScheduleBuilder {
private final PrivacyParameters privacyParameters;
private final boolean isRevertReasonEnabled;
private final FeeMarket feeMarket = FeeMarket.eip1559();
private final BadBlockManager badBlockManager = new BadBlockManager();
public ProtocolScheduleBuilder(
final GenesisConfigOptions config,
@ -288,6 +290,7 @@ public class ProtocolScheduleBuilder {
number,
protocolSpecAdapter
.apply(definition)
.badBlocksManager(badBlockManager)
.privacyParameters(privacyParameters)
.privateTransactionValidatorBuilder(
() -> new PrivateTransactionValidator(protocolSchedule.getChainId()))

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.config.experimental.ExperimentalEIPs;
import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.Wei;
@ -74,6 +75,8 @@ public class ProtocolSpec {
private final TransactionGasBudgetCalculator gasBudgetCalculator;
private final BadBlockManager badBlockManager;
/**
* Creates a new protocol specification instance.
*
@ -99,6 +102,7 @@ public class ProtocolSpec {
* @param transactionPriceCalculator the transaction price calculator to use.
* @param eip1559 an {@link Optional} wrapping {@link EIP1559} manager class if appropriate.
* @param gasBudgetCalculator the gas budget calculator to use.
* @param badBlockManager the cache to use to keep invalid blocks
*/
public ProtocolSpec(
final String name,
@ -122,7 +126,8 @@ public class ProtocolSpec {
final GasCalculator gasCalculator,
final TransactionPriceCalculator transactionPriceCalculator,
final Optional<EIP1559> eip1559,
final TransactionGasBudgetCalculator gasBudgetCalculator) {
final TransactionGasBudgetCalculator gasBudgetCalculator,
final BadBlockManager badBlockManager) {
this.name = name;
this.evm = evm;
this.transactionValidator = transactionValidator;
@ -145,6 +150,7 @@ public class ProtocolSpec {
this.transactionPriceCalculator = transactionPriceCalculator;
this.eip1559 = eip1559;
this.gasBudgetCalculator = gasBudgetCalculator;
this.badBlockManager = badBlockManager;
}
/**
@ -335,4 +341,13 @@ public class ProtocolSpec {
public TransactionGasBudgetCalculator getGasBudgetCalculator() {
return gasBudgetCalculator;
}
/**
* Returns the bad blocks manager
*
* @return the bad blocks manager
*/
public BadBlockManager getBadBlocksManager() {
return badBlockManager;
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
@ -69,6 +70,7 @@ public class ProtocolSpecBuilder {
private Optional<EIP1559> eip1559 = Optional.empty();
private TransactionGasBudgetCalculator gasBudgetCalculator =
TransactionGasBudgetCalculator.frontier();
private BadBlockManager badBlockManager;
public ProtocolSpecBuilder gasCalculator(final Supplier<GasCalculator> gasCalculatorBuilder) {
this.gasCalculatorBuilder = gasCalculatorBuilder;
@ -230,6 +232,11 @@ public class ProtocolSpecBuilder {
return this;
}
public ProtocolSpecBuilder badBlocksManager(final BadBlockManager badBlockManager) {
this.badBlockManager = badBlockManager;
return this;
}
public ProtocolSpec build(final ProtocolSchedule protocolSchedule) {
checkNotNull(gasCalculatorBuilder, "Missing gasCalculator");
checkNotNull(evmBuilder, "Missing operation registry");
@ -255,6 +262,7 @@ public class ProtocolSpecBuilder {
checkNotNull(privacyParameters, "Missing privacy parameters");
checkNotNull(transactionPriceCalculator, "Missing transaction price calculator");
checkNotNull(eip1559, "Missing eip1559 optional wrapper");
checkNotNull(badBlockManager, "Missing bad blocks manager");
final GasCalculator gasCalculator = gasCalculatorBuilder.get();
final EVM evm = evmBuilder.apply(gasCalculator);
@ -324,7 +332,8 @@ public class ProtocolSpecBuilder {
}
final BlockValidator blockValidator =
blockValidatorBuilder.apply(blockHeaderValidator, blockBodyValidator, blockProcessor);
blockValidatorBuilder.apply(
blockHeaderValidator, blockBodyValidator, blockProcessor, badBlockManager);
final BlockImporter blockImporter = blockImporterBuilder.apply(blockValidator);
return new ProtocolSpec(
name,
@ -348,7 +357,8 @@ public class ProtocolSpecBuilder {
gasCalculator,
transactionPriceCalculator,
eip1559,
gasBudgetCalculator);
gasBudgetCalculator,
badBlockManager);
}
public interface TransactionProcessorBuilder {
@ -386,7 +396,8 @@ public class ProtocolSpecBuilder {
BlockValidator apply(
BlockHeaderValidator blockHeaderValidator,
BlockBodyValidator blockBodyValidator,
BlockProcessor blockProcessor);
BlockProcessor blockProcessor,
BadBlockManager badBlockManager);
}
public interface BlockImporterBuilder {

@ -0,0 +1,240 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.BlockBodyValidator;
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.BlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
public class MainnetBlockValidatorTest {
private final BlockHeaderValidator blockHeaderValidator = mock(BlockHeaderValidator.class);
private final BlockBodyValidator blockBodyValidator = mock(BlockBodyValidator.class);
private final BlockProcessor blockProcessor = mock(BlockProcessor.class);
private final ProtocolContext protocolContext = mock(ProtocolContext.class);
protected final MutableBlockchain blockchain = mock(MutableBlockchain.class);
protected final WorldStateArchive worldStateArchive = mock(WorldStateArchive.class);
private final BadBlockManager badBlockManager = new BadBlockManager();
private MainnetBlockValidator mainnetBlockValidator;
private Block badBlock;
@Before
public void setup() {
when(protocolContext.getBlockchain()).thenReturn(blockchain);
when(protocolContext.getWorldStateArchive()).thenReturn(worldStateArchive);
mainnetBlockValidator =
new MainnetBlockValidator(
blockHeaderValidator, blockBodyValidator, blockProcessor, badBlockManager);
badBlock =
new BlockDataGenerator()
.block(
BlockDataGenerator.BlockOptions.create()
.setBlockNumber(2)
.hasTransactions(false)
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions()));
}
@Test
public void shouldDetectAndCacheInvalidBlocksWhenParentBlockNotPresent() {
when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.empty());
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void shouldDetectAndCacheInvalidBlocksWhenHeaderInvalid() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
when(blockHeaderValidator.validateHeader(
any(BlockHeader.class),
any(BlockHeader.class),
eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(false);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void shouldDetectAndCacheInvalidBlocksWhenParentWorldStateNotAvailable() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
when(blockHeaderValidator.validateHeader(
any(BlockHeader.class),
any(BlockHeader.class),
eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class))).thenReturn(Optional.empty());
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void shouldDetectAndCacheInvalidBlocksWhenProcessBlockFailed() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
when(blockHeaderValidator.validateHeader(
any(BlockHeader.class),
any(BlockHeader.class),
eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn(
new BlockProcessor.Result() {
@SuppressWarnings("unchecked")
@Override
public List<TransactionReceipt> getReceipts() {
return Collections.EMPTY_LIST;
}
@Override
public boolean isSuccessful() {
return false;
}
});
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void shouldDetectAndCacheInvalidBlocksWhenBodyInvalid() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
when(blockHeaderValidator.validateHeader(
any(BlockHeader.class),
any(BlockHeader.class),
eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn(
new BlockProcessor.Result() {
@SuppressWarnings("unchecked")
@Override
public List<TransactionReceipt> getReceipts() {
return Collections.EMPTY_LIST;
}
@Override
public boolean isSuccessful() {
return true;
}
});
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(1);
}
@Test
public void shouldNotCacheWhenValidBlocks() {
when(blockchain.getBlockHeader(any(Hash.class)))
.thenReturn(Optional.of(new BlockHeaderTestFixture().buildHeader()));
when(blockHeaderValidator.validateHeader(
any(BlockHeader.class),
any(BlockHeader.class),
eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn(
new BlockProcessor.Result() {
@SuppressWarnings("unchecked")
@Override
public List<TransactionReceipt> getReceipts() {
return Collections.EMPTY_LIST;
}
@Override
public boolean isSuccessful() {
return true;
}
});
when(blockBodyValidator.validateBody(
eq(protocolContext),
eq(badBlock),
any(),
any(),
eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true);
assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks()).isEmpty();
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.vm;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
@ -100,6 +101,7 @@ public class VMReferenceTest extends AbstractRetryingTest {
MainnetProtocolSpecs.frontierDefinition(OptionalInt.empty(), OptionalInt.empty())
.privacyParameters(PrivacyParameters.DEFAULT)
.privateTransactionValidatorBuilder(() -> new PrivateTransactionValidator(CHAIN_ID))
.badBlocksManager(new BadBlockManager())
.build(new MutableProtocolSchedule(CHAIN_ID));
final ReturnStack returnStack = new ReturnStack();

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.eth.sync;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent.EventType;
import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -298,26 +299,30 @@ public class BlockPropagationManager {
"Incapable of retrieving header from non-existent parent of "
+ block.getHeader().getNumber()
+ "."));
final ProtocolSpec protocolSpec =
protocolSchedule.getByBlockNumber(block.getHeader().getNumber());
final BlockHeaderValidator blockHeaderValidator = protocolSpec.getBlockHeaderValidator();
final BadBlockManager badBlockManager = protocolSpec.getBadBlocksManager();
return ethContext
.getScheduler()
.scheduleSyncWorkerTask(
() -> validateAndProcessPendingBlock(blockHeaderValidator, block, parent));
() ->
validateAndProcessPendingBlock(
blockHeaderValidator, block, parent, badBlockManager));
}
private CompletableFuture<Block> validateAndProcessPendingBlock(
final BlockHeaderValidator blockHeaderValidator,
final Block block,
final BlockHeader parent) {
final BlockHeader parent,
final BadBlockManager badBlockManager) {
if (blockHeaderValidator.validateHeader(
block.getHeader(), parent, protocolContext, HeaderValidationMode.FULL)) {
ethContext.getScheduler().scheduleSyncWorkerTask(() -> broadcastBlock(block, parent));
return runImportTask(block);
} else {
importingBlocks.remove(block.getHash());
badBlockManager.addBadBlock(block);
LOG.warn(
"Failed to import announced block {} ({}).",
block.getHeader().getNumber(),

@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException;
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import java.util.function.Function;
import java.util.stream.Stream;
@ -69,10 +70,9 @@ public class CheckpointHeaderValidationStep
}
private boolean isValid(final BlockHeader expectedParent, final BlockHeader firstHeaderToImport) {
final BlockHeaderValidator validator =
protocolSchedule
.getByBlockNumber(firstHeaderToImport.getNumber())
.getBlockHeaderValidator();
final ProtocolSpec protocolSpec =
protocolSchedule.getByBlockNumber(firstHeaderToImport.getNumber());
final BlockHeaderValidator validator = protocolSpec.getBlockHeaderValidator();
return validator.validateHeader(
firstHeaderToImport,
expectedParent,

@ -18,13 +18,17 @@ import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractGetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetBlockFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask;
import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy;
import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException;
@ -195,16 +199,42 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
child =
(headerIndex == segmentLength - 1) ? referenceHeader : headers[headerIndex + 1];
}
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(child.getNumber());
final BadBlockManager badBlockManager = protocolSpec.getBadBlocksManager();
if (!validateHeader(child, header)) {
// Invalid headers - disconnect from peer
LOG.debug(
"Received invalid headers from peer, disconnecting from: {}",
headersResult.getPeer());
headersResult.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL);
future.completeExceptionally(
new InvalidBlockException(
"Header failed validation.", child.getNumber(), child.getHash()));
final BlockHeader invalidBlock = child;
// even though the header is known bad we are downloading the block body for the
// debug_badBlocks RPC
final AbstractPeerTask<Block> getBlockTask =
GetBlockFromPeerTask.create(
protocolSchedule,
ethContext,
child.getHash(),
child.getNumber(),
metricsSystem)
.assignPeer(headersResult.getPeer());
getBlockTask
.run()
.whenComplete(
(blockPeerTaskResult, error) -> {
if (error == null && blockPeerTaskResult.getResult() != null) {
badBlockManager.addBadBlock(blockPeerTaskResult.getResult());
}
headersResult.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL);
LOG.debug(
"Received invalid headers from peer, disconnecting from: {}",
headersResult.getPeer());
future.completeExceptionally(
new InvalidBlockException(
"Header failed validation.",
invalidBlock.getNumber(),
invalidBlock.getHash()));
});
return future;
}
headers[headerIndex] = header;

@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
@ -47,6 +48,7 @@ import org.hyperledger.besu.ethereum.eth.messages.NewBlockHashesMessage;
import org.hyperledger.besu.ethereum.eth.messages.NewBlockMessage;
import org.hyperledger.besu.ethereum.eth.sync.state.PendingBlocks;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@ -60,6 +62,8 @@ import java.util.function.Supplier;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class BlockPropagationManagerTest {
@ -641,4 +645,49 @@ public class BlockPropagationManagerTest {
verify(blockBroadcaster, times(1)).propagate(block, totalDifficulty);
}
@SuppressWarnings("unchecked")
@Test
public void shouldDetectAndCacheInvalidBlocks() {
final EthScheduler ethScheduler = mock(EthScheduler.class);
when(ethScheduler.scheduleSyncWorkerTask(any(Supplier.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(final InvocationOnMock invocation) throws Throwable {
return invocation.getArgument(0, Supplier.class).get();
}
});
final EthContext ethContext =
new EthContext(
new EthPeers("eth", TestClock.fixed(), metricsSystem), new EthMessages(), ethScheduler);
final BlockPropagationManager blockPropagationManager =
new BlockPropagationManager(
syncConfig,
protocolSchedule,
protocolContext,
ethContext,
syncState,
pendingBlocks,
metricsSystem,
blockBroadcaster);
blockchainUtil.importFirstBlocks(2);
final Block firstBlock = blockchainUtil.getBlock(1);
final BadBlockManager badBlocksManager =
protocolSchedule.getByBlockNumber(1).getBadBlocksManager();
final Block badBlock =
new BlockDataGenerator()
.block(
BlockDataGenerator.BlockOptions.create()
.setBlockNumber(1)
.setParentHash(firstBlock.getHash())
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions()));
assertThat(badBlocksManager.getBadBlocks()).isEmpty();
blockPropagationManager.importOrSavePendingBlock(badBlock);
assertThat(badBlocksManager.getBadBlocks().size()).isEqualTo(1);
verify(ethScheduler, times(1)).scheduleSyncWorkerTask(any(Supplier.class));
}
}

@ -53,7 +53,8 @@ public class NoRewardProtocolScheduleWrapper implements ProtocolSchedule {
new MainnetBlockValidator(
original.getBlockHeaderValidator(),
original.getBlockBodyValidator(),
noRewardBlockProcessor);
noRewardBlockProcessor,
original.getBadBlocksManager());
final BlockImporter noRewardBlockImporter = new MainnetBlockImporter(noRewardBlockValidator);
return new ProtocolSpec(
original.getName(),
@ -77,7 +78,8 @@ public class NoRewardProtocolScheduleWrapper implements ProtocolSchedule {
original.getGasCalculator(),
original.getTransactionPriceCalculator(),
original.getEip1559(),
original.getGasBudgetCalculator());
original.getGasBudgetCalculator(),
original.getBadBlocksManager());
}
@Override

Loading…
Cancel
Save