Add standard trace bad block to file JSON RPC method (#1403)

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
pull/1413/head
matkt 4 years ago committed by GitHub
parent b5e8f4f368
commit cfaccb6545
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java
  3. 78
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFile.java
  4. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBlockToFile.java
  5. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java
  6. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java
  7. 99
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStandardTraceBadBlockToFileTest.java
  8. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java
  9. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java
  10. 18
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java

@ -5,6 +5,7 @@
### Additions and Improvements
* Added support for the upcoming YOLOv2 ephemeral testnet and removed the flag for the deprecated YOLOv1 ephemeral testnet. [#1386](https://github.com/hyperledger/besu/pull/1386)
* Added `debug_standardTraceBlockToFile` JSON-RPC API. This API accepts a block hash and will replay the block. It returns a list of files containing the result of the trace (one file per transaction). [\#1392](https://github.com/hyperledger/besu/pull/1392)
* Added `debug_standardTraceBadBlockToFile` JSON-RPC API. This API is similar to `debug_standardTraceBlockToFile`, but can be used to obtain info about a block which has been rejected as invalid. [\#1403](https://github.com/hyperledger/besu/pull/1403)
* Added support for EIP-2929 to YOLOv2. [#1387](https://github.com/hyperledger/besu/pull/1387)
* Added `--start-block` and `--end-block` to the `blocks import` subcommand [\#1399](https://github.com/hyperledger/besu/pull/1399)

@ -38,6 +38,7 @@ public enum RpcMethod {
DEBUG_TRACE_BLOCK_BY_HASH("debug_traceBlockByHash"),
DEBUG_TRACE_BLOCK_BY_NUMBER("debug_traceBlockByNumber"),
DEBUG_STANDARD_TRACE_BLOCK_TO_FILE("debug_standardTraceBlockToFile"),
DEBUG_STANDARD_TRACE_BAD_BLOCK_TO_FILE("debug_standardTraceBadBlockToFile"),
DEBUG_TRACE_TRANSACTION("debug_traceTransaction"),
DEBUG_BATCH_RAW_TRANSACTION("debug_batchSendRawTransaction"),
DEBUG_GET_BAD_BLOCKS("debug_getBadBlocks"),

@ -0,0 +1,78 @@
/*
* 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.parameters.TransactionTraceParams;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
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.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Supplier;
public class DebugStandardTraceBadBlockToFile extends DebugStandardTraceBlockToFile
implements JsonRpcMethod {
private final ProtocolSchedule protocolSchedule;
public DebugStandardTraceBadBlockToFile(
final Supplier<TransactionTracer> transactionTracerSupplier,
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final Path dataDir) {
super(transactionTracerSupplier, blockchainQueries, dataDir);
this.protocolSchedule = protocolSchedule;
}
@Override
public String getName() {
return RpcMethod.DEBUG_STANDARD_TRACE_BAD_BLOCK_TO_FILE.getMethodName();
}
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final Hash blockHash = requestContext.getRequiredParameter(0, Hash.class);
final Optional<TransactionTraceParams> transactionTraceParams =
requestContext.getOptionalParameter(1, TransactionTraceParams.class);
final Blockchain blockchain = blockchainQueries.get().getBlockchain();
final ProtocolSpec protocolSpec =
protocolSchedule.getByBlockNumber(blockchain.getChainHeadHeader().getNumber());
final BadBlockManager badBlockManager = protocolSpec.getBadBlocksManager();
return badBlockManager
.getBadBlock(blockHash)
.map(
block ->
(JsonRpcResponse)
new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
traceBlock(block, transactionTraceParams)))
.orElse(
new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND));
}
}

@ -38,8 +38,8 @@ import com.google.common.base.Suppliers;
public class DebugStandardTraceBlockToFile implements JsonRpcMethod {
protected final Supplier<BlockchainQueries> blockchainQueries;
private final Supplier<TransactionTracer> transactionTracerSupplier;
private final Supplier<BlockchainQueries> blockchainQueries;
private final Path dataDir;
public DebugStandardTraceBlockToFile(
@ -77,7 +77,7 @@ public class DebugStandardTraceBlockToFile implements JsonRpcMethod {
requestContext.getRequest().getId(), JsonRpcError.BLOCK_NOT_FOUND));
}
private List<String> traceBlock(
protected List<String> traceBlock(
final Block block, final Optional<TransactionTraceParams> transactionTraceParams) {
return transactionTracerSupplier
.get()

@ -124,8 +124,12 @@ public class BlockReplay {
private <T> Optional<T> performActionWithBlock(
final Hash blockHash, final BlockAction<T> action) {
return getBlock(blockHash)
.flatMap(block -> performActionWithBlock(block.getHeader(), block.getBody(), action));
Optional<Block> maybeBlock = getBlock(blockHash);
if (maybeBlock.isEmpty()) {
maybeBlock = getBadBlock(blockHash);
}
return maybeBlock.flatMap(
block -> performActionWithBlock(block.getHeader(), block.getBody(), action));
}
private <T> Optional<T> performActionWithBlock(
@ -161,6 +165,12 @@ public class BlockReplay {
return Optional.empty();
}
private Optional<Block> getBadBlock(final Hash blockHash) {
final ProtocolSpec protocolSpec =
protocolSchedule.getByBlockNumber(blockchain.getChainHeadHeader().getNumber());
return protocolSpec.getBadBlocksManager().getBadBlock(blockHash);
}
@FunctionalInterface
private interface BlockAction<T> {
Optional<T> perform(

@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRa
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.DebugStandardTraceBadBlockToFile;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStandardTraceBlockToFile;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRangeAt;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock;
@ -90,6 +91,11 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
new DebugBatchSendRawTransaction(transactionPool),
new DebugGetBadBlocks(blockchainQueries, protocolSchedule, blockResult),
new DebugStandardTraceBlockToFile(
() -> new TransactionTracer(blockReplay), blockchainQueries, dataDir));
() -> new TransactionTracer(blockReplay), blockchainQueries, dataDir),
new DebugStandardTraceBadBlockToFile(
() -> new TransactionTracer(blockReplay),
blockchainQueries,
protocolSchedule,
dataDir));
}
}

@ -0,0 +1,99 @@
/*
* 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.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
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.processor.TransactionTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
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.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class DebugStandardTraceBadBlockToFileTest {
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder();
private final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
private final Blockchain blockchain = mock(Blockchain.class);
private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class);
private final TransactionTracer transactionTracer = mock(TransactionTracer.class);
private final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
private final DebugStandardTraceBadBlockToFile debugStandardTraceBadBlockToFile =
new DebugStandardTraceBadBlockToFile(
() -> transactionTracer, blockchainQueries, protocolSchedule, folder.getRoot().toPath());
@Test
public void nameShouldBeDebugTraceTransaction() {
assertThat(debugStandardTraceBadBlockToFile.getName())
.isEqualTo("debug_standardTraceBadBlockToFile");
}
@SuppressWarnings("rawtypes")
@Test
public void shouldTraceTheTransactionUsingTheTransactionTracer() {
final BlockDataGenerator blockGenerator = new BlockDataGenerator();
final Block genesis = blockGenerator.genesisBlock();
final Block block =
blockGenerator.block(
new BlockDataGenerator.BlockOptions().setParentHash(genesis.getHeader().getHash()));
final Object[] params = new Object[] {block.getHash(), new HashMap<>()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "debug_standardTraceBadBlockToFile", params));
final List<String> paths = new ArrayList<>();
paths.add("path-1");
final BadBlockManager badBlockManager = new BadBlockManager();
badBlockManager.addBadBlock(block);
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader();
when(protocolSpec.getBadBlocksManager()).thenReturn(badBlockManager);
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchain.getChainHeadHeader()).thenReturn(new BlockHeaderTestFixture().buildHeader());
when(protocolSchedule.getByBlockNumber(blockHeader.getNumber())).thenReturn(protocolSpec);
when(transactionTracer.traceTransactionToFile(eq(block.getHash()), any(), any(), any()))
.thenReturn(paths);
final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) debugStandardTraceBadBlockToFile.response(request);
final List result = (ArrayList) response.getResult();
assertThat(result.size()).isEqualTo(1);
}
}

@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ImmutableTransactionTraceParams;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockBody;
@ -113,6 +114,8 @@ public class TransactionTracerTest {
when(protocolSchedule.getByBlockNumber(12)).thenReturn(protocolSpec);
when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor);
when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase);
when(blockchain.getChainHeadHeader()).thenReturn(blockHeader);
when(protocolSpec.getBadBlocksManager()).thenReturn(new BadBlockManager());
}
@Test
@ -259,7 +262,6 @@ public class TransactionTracerTest {
transactions,
Optional.of(ImmutableTransactionTraceParams.builder().build()),
traceDir.getRoot().toPath());
;
assertThat(transactionTraces.size()).isEqualTo(1);
assertThat(Files.readString(Path.of(transactionTraces.get(0))))

@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Hash;
import java.util.Collection;
import java.util.Optional;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
@ -46,4 +47,14 @@ public class BadBlockManager {
public Collection<Block> getBadBlocks() {
return badBlocks.asMap().values();
}
/**
* Return an invalid block based on the hash
*
* @param hash of the block
* @return an invalid block
*/
public Optional<Block> getBadBlock(final Hash hash) {
return Optional.ofNullable(badBlocks.getIfPresent(hash));
}
}

@ -237,4 +237,22 @@ public class MainnetBlockValidatorTest {
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlocks()).isEmpty();
}
@Test
public void shouldReturnBadBlockBasedOnTheHash() {
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);
mainnetBlockValidator.validateAndProcessBlock(
protocolContext,
badBlock,
HeaderValidationMode.DETACHED_ONLY,
HeaderValidationMode.DETACHED_ONLY);
assertThat(badBlockManager.getBadBlock(badBlock.getHash())).containsSame(badBlock);
}
}

Loading…
Cancel
Save