Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

[WIP] Add block trace RPC methods (#1055) #1088

Merged
merged 13 commits into from
Apr 15, 2019

Conversation

kziemianek
Copy link
Contributor

PR description

Adds rpc methods to debug block by providing block number, block hash or block itself encoded by RLP.

Fixed Issue(s)

fixes: #1055

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({"gas", "structLogs"})
public class DebugTraceBlockResult {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing value property (it's listed in issue), any hints how block's value can be computed ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue description is missing an important element here unforunately - the result should be an array of transaction trace results. So:

[
{
  gas: 999,
  returnValue: "",
  structLogs: [{
      depth: 1,
      error: "",
      gas: 99999,
      gasCost: 2,
      memory: null,
      op: "PUSH1",
      pc: 0,
      stack: [],
      storage: {}
  },
  ... (more transactions)
]

The returnValue is then the return value of the transaction the same way DebugTraceTransactionResult extracts it. In fact, I suspect DebugTraceBlockResult isn't required and the success response is just return new JsonRpcSuccessResponse(request.getId(), listOfDebugTraceTransactionResult)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, i'll change it.

@ajsutton ajsutton self-assigned this Mar 12, 2019
Copy link
Contributor

@ajsutton ajsutton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really promising, thanks. I know this is a work in progress so apologies if I'm pointing things out that are already on your radar but figured I'd look through and give early feedback. Hopefully it's helpful.

final String input = parameters.required(request.getParams(), 0, String.class);
final Block block =
Block.readFrom(
RLP.input(BytesValue.fromHexString(input)), MainnetBlockHashFunction::createHash);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to avoid hard coding MainnetBlockHashFunction here and instead use a ScheduleBasedBlockHashFunction so that it automatically selects the right hash function based on the protocol schedule. My suggestion would be to add a BlockHashFunction parameter to the constructor and create the ScheduleBasedBlockHashFunction back up in JsonRpcMethodsFactory so DebugTraceBlock avoids having a direct dependency on ProtocolSchedule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely, I wasn't aware of ScheduleBasedBlockHashFunction and had to pass something.

RLP.input(BytesValue.fromHexString(input)), MainnetBlockHashFunction::createHash);
DebugTraceBlockResult result =
blockTracer.trace(block).map(DebugTraceBlockResult::new).orElse(null);
return new JsonRpcSuccessResponse(request.getId(), result);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should return an error response with a message if the block parent isn't on the block chain rather than just success with a null result.

.collect(Collectors.toList());
return Optional.of(new BlockTrace(transactionTraces));
})
.orElse(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we could avoid duplication through this class by setting up the versions of methods that accept a Hash to just lookup the block by hash and if it's present delegate to the version that accepts a Block rather than duplicating code.


private final BlockReplay.Action<TransactionTrace> replayAction =
(transaction, header, blockchain, mutableWorldState, transactionProcessor) -> {
DebugOperationTracer tracer = new DebugOperationTracer(TraceOptions.DEFAULT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have the TraceOptions come from an optional extra param to the JSON-RPC calls rather than hard coding to default.

@kziemianek
Copy link
Contributor Author

@ajsutton thanks, I really apprecieate your comments and I'll follow Your suggestions, new commits comming soon.

@kziemianek kziemianek closed this Mar 16, 2019
@kziemianek kziemianek reopened this Mar 16, 2019
Copy link
Contributor

@ajsutton ajsutton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good - just a few minor tweaks required I think. Sorry it took me so long to review I somehow missed the new commits coming in. I do my best to keep up with everything, but feel free to @ mention me when I should take another look.

public JsonRpcResponse response(final JsonRpcRequest request) {
final String input = parameters.required(request.getParams(), 0, String.class);
final Block block =
Block.readFrom(RLP.input(BytesValue.fromHexString(input)), this.blockHashFunction);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may throw RLPException if the input isn't valid RLP which we should probably catch and return a meaningful error. Currently it would result in an internal server error response.


public interface DebugTraceJsonRpcMethod {

default TraceOptions getTraceOptions(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would probably make more sense as a static method rather than a default method. It's probably clearer to pass in the transactionTraceparamsParameterIndex as a param to the method than using the second default method.

.orElse(Optional.empty());
}

private <T> Optional<T> performActionPerBlockTransaction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method name is a bit misleading. It sounds like it's looping through calling action for each transaction in the block but actually appears to just call the action once. So maybe performActionWithBlock would be a better name?

transaction, blockHeader, blockchain, worldState, transactionProcessor);
});
@FunctionalInterface
private interface BlockTransactionAction<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be BlockAction?

}

@FunctionalInterface
public interface Action<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe this is now TransactionAction?

}

public Optional<BlockTrace> trace(final Block block, final DebugOperationTracer tracer) {
return Optional.of(blockReplay.block(block, this.prepareReplayAction(tracer)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the this. prefix isn't required here.

}

@Test
public void shouldReturnErrorResponseWhenParenBlockMissing() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing t at the end of Paren.

Copy link
Contributor

@ajsutton ajsutton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied fixes the last few suggested tweaks so LGTM.

@ajsutton ajsutton merged commit ec452c3 into PegaSysEng:master Apr 15, 2019
@kziemianek
Copy link
Contributor Author

Sorry @ajsutton , I'm very busy lately. Thanks for commit and merge.

@ajsutton
Copy link
Contributor

@kziemianek Thank you for doing all the hard work. It's great to have this APIs available.

notlesh pushed a commit to notlesh/pantheon that referenced this pull request Apr 24, 2019
Implements debug_traceBlock, debug_traceBlockByHash and debug_traceBlockByNumber methods.
notlesh pushed a commit to notlesh/pantheon that referenced this pull request May 4, 2019
Implements debug_traceBlock, debug_traceBlockByHash and debug_traceBlockByNumber methods.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants