Skip to content

Commit

Permalink
Add block trace RPC methods (PegaSysEng#1088)
Browse files Browse the repository at this point in the history
Implements debug_traceBlock, debug_traceBlockByHash and debug_traceBlockByNumber methods.
  • Loading branch information
kziemianek authored and notlesh committed May 4, 2019
1 parent f65c3d8 commit 35e9a9e
Show file tree
Hide file tree
Showing 15 changed files with 777 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminRemovePeer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugMetrics;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugStorageRangeAt;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceBlock;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceBlockByHash;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceBlockByNumber;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceTransaction;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthAccounts;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthBlockNumber;
Expand Down Expand Up @@ -87,10 +90,12 @@
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaSendRawTransaction;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockReplay;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.BlockResultFactory;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
Expand Down Expand Up @@ -236,7 +241,14 @@ public Map<String, JsonRpcMethod> methods(
new DebugTraceTransaction(
blockchainQueries, new TransactionTracer(blockReplay), parameter),
new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay),
new DebugMetrics(metricsSystem));
new DebugMetrics(metricsSystem),
new DebugTraceBlock(
parameter,
new BlockTracer(blockReplay),
ScheduleBasedBlockHashFunction.create(protocolSchedule),
blockchainQueries),
new DebugTraceBlockByNumber(parameter, new BlockTracer(blockReplay), blockchainQueries),
new DebugTraceBlockByHash(parameter, new BlockTracer(blockReplay)));
}
if (rpcApis.contains(RpcApis.NET)) {
addMethods(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2019 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.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;

import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockHashFunction;
import tech.pegasys.pantheon.ethereum.debug.TraceOptions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.TransactionTraceParams;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTrace;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.DebugTraceTransactionResult;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.util.Collection;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class DebugTraceBlock implements JsonRpcMethod {

private static final Logger LOG = LogManager.getLogger();
private final JsonRpcParameter parameters;
private final BlockTracer blockTracer;
private final BlockHashFunction blockHashFunction;
private final BlockchainQueries blockchain;

public DebugTraceBlock(
final JsonRpcParameter parameters,
final BlockTracer blockTracer,
final BlockHashFunction blockHashFunction,
final BlockchainQueries blockchain) {
this.parameters = parameters;
this.blockTracer = blockTracer;
this.blockHashFunction = blockHashFunction;
this.blockchain = blockchain;
}

@Override
public String getName() {
return "debug_traceBlock";
}

@Override
public JsonRpcResponse response(final JsonRpcRequest request) {
final String input = parameters.required(request.getParams(), 0, String.class);
final Block block;
try {
block = Block.readFrom(RLP.input(BytesValue.fromHexString(input)), this.blockHashFunction);
} catch (final RLPException e) {
LOG.debug("Failed to parse block RLP", e);
return new JsonRpcErrorResponse(request.getId(), JsonRpcError.INVALID_PARAMS);
}
final TraceOptions traceOptions =
parameters
.optional(request.getParams(), 1, TransactionTraceParams.class)
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);

if (this.blockchain.blockByHash(block.getHeader().getParentHash()).isPresent()) {
final Collection<DebugTraceTransactionResult> results =
blockTracer
.trace(block, new DebugOperationTracer(traceOptions))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of)
.orElse(null);
return new JsonRpcSuccessResponse(request.getId(), results);
} else {
return new JsonRpcErrorResponse(request.getId(), JsonRpcError.PARENT_BLOCK_NOT_FOUND);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2019 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.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;

import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.debug.TraceOptions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.TransactionTraceParams;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTrace;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.DebugTraceTransactionResult;
import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer;

import java.util.Collection;

public class DebugTraceBlockByHash implements JsonRpcMethod {

private final JsonRpcParameter parameters;
private final BlockTracer blockTracer;

public DebugTraceBlockByHash(final JsonRpcParameter parameters, final BlockTracer blockTracer) {
this.parameters = parameters;
this.blockTracer = blockTracer;
}

@Override
public String getName() {
return "debug_traceBlockByHash";
}

@Override
public JsonRpcResponse response(final JsonRpcRequest request) {
final Hash blockHash = parameters.required(request.getParams(), 0, Hash.class);
final TraceOptions traceOptions =
parameters
.optional(request.getParams(), 1, TransactionTraceParams.class)
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);

final Collection<DebugTraceTransactionResult> results =
blockTracer
.trace(blockHash, new DebugOperationTracer(traceOptions))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of)
.orElse(null);
return new JsonRpcSuccessResponse(request.getId(), results);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2019 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.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;

import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.debug.TraceOptions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.TransactionTraceParams;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTrace;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.DebugTraceTransactionResult;
import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer;

import java.util.Collection;
import java.util.Optional;

public class DebugTraceBlockByNumber implements JsonRpcMethod {

private final JsonRpcParameter parameters;
private final BlockTracer blockTracer;
private final BlockchainQueries blockchain;

public DebugTraceBlockByNumber(
final JsonRpcParameter parameters,
final BlockTracer blockTracer,
final BlockchainQueries blockchain) {
this.parameters = parameters;
this.blockTracer = blockTracer;
this.blockchain = blockchain;
}

@Override
public String getName() {
return "debug_traceBlockByNumber";
}

@Override
public JsonRpcResponse response(final JsonRpcRequest request) {
final Long blockNumber = parameters.required(request.getParams(), 0, Long.class);
final Optional<Hash> blockHash = this.blockchain.getBlockHashByNumber(blockNumber);
final TraceOptions traceOptions =
parameters
.optional(request.getParams(), 1, TransactionTraceParams.class)
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);

final Collection<DebugTraceTransactionResult> results =
blockHash
.map(
hash ->
blockTracer
.trace(hash, new DebugOperationTracer(traceOptions))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of))
.orElse(null)
.get();
return new JsonRpcSuccessResponse(request.getId(), results);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import tech.pegasys.pantheon.ethereum.debug.TraceOptions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTraceParams;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.TransactionTraceParams;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTracer;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.TransactionWithMetadata;
Expand Down Expand Up @@ -50,13 +50,16 @@ public String getName() {
@Override
public JsonRpcResponse response(final JsonRpcRequest request) {
final Hash hash = parameters.required(request.getParams(), 0, Hash.class);
final Optional<TransactionTraceParams> transactionTraceParams =
parameters.optional(request.getParams(), 1, TransactionTraceParams.class);
final Optional<TransactionWithMetadata> transactionWithMetadata =
blockchain.transactionByHash(hash);
if (transactionWithMetadata.isPresent()) {
DebugTraceTransactionResult debugTraceTransactionResult =
debugTraceTransactionResult(hash, transactionWithMetadata.get(), transactionTraceParams);
final TraceOptions traceOptions =
parameters
.optional(request.getParams(), 1, TransactionTraceParams.class)
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);
final DebugTraceTransactionResult debugTraceTransactionResult =
debugTraceTransactionResult(hash, transactionWithMetadata.get(), traceOptions);

return new JsonRpcSuccessResponse(request.getId(), debugTraceTransactionResult);
} else {
Expand All @@ -67,12 +70,8 @@ public JsonRpcResponse response(final JsonRpcRequest request) {
private DebugTraceTransactionResult debugTraceTransactionResult(
final Hash hash,
final TransactionWithMetadata transactionWithMetadata,
final Optional<TransactionTraceParams> transactionTraceParams) {
final TraceOptions traceOptions) {
final Hash blockHash = transactionWithMetadata.getBlockHash();
final TraceOptions traceOptions =
transactionTraceParams
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);

final DebugOperationTracer execTracer = new DebugOperationTracer(traceOptions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* 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.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor;
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters;

import tech.pegasys.pantheon.ethereum.debug.TraceOptions;

Expand Down
Loading

0 comments on commit 35e9a9e

Please sign in to comment.