Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transaction hash for debug trace responses #8205

Merged
merged 9 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
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.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionDetails;
import org.hyperledger.besu.plugin.services.rpc.RpcResponseType;
import org.hyperledger.besu.testutil.BlockTestUtil;

Expand Down Expand Up @@ -60,22 +60,20 @@ public void setUp() {
@Test
public void debugTraceTransactionSuccessTest() {
final Map<String, Boolean> map = Map.of("disableStorage", true);
final Object[] params =
new Object[] {
Hash.fromHexString("0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310"),
map
};
final Hash trxHash =
Hash.fromHexString("0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310");
final Object[] params = new Object[] {trxHash, map};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", DEBUG_TRACE_TRANSACTION, params));

final JsonRpcResponse response = method.response(request);
assertThat(response.getType()).isEqualTo(RpcResponseType.SUCCESS);
DebugTraceTransactionResult debugTraceTransactionResult =
(DebugTraceTransactionResult) ((JsonRpcSuccessResponse) response).getResult();
assertThat(debugTraceTransactionResult.getGas()).isEqualTo(23705L);
assertThat(debugTraceTransactionResult.getReturnValue()).isEmpty();
assertThat(debugTraceTransactionResult.failed()).isFalse();
assertThat(debugTraceTransactionResult.getStructLogs()).hasSize(106);
DebugTraceTransactionDetails debugTraceTransactionDetails =
(DebugTraceTransactionDetails) ((JsonRpcSuccessResponse) response).getResult();
assertThat(debugTraceTransactionDetails.getGas()).isEqualTo(23705L);
assertThat(debugTraceTransactionDetails.getReturnValue()).isEmpty();
assertThat(debugTraceTransactionDetails.failed()).isFalse();
assertThat(debugTraceTransactionDetails.getStructLogs()).hasSize(106);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionDetails;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.debug.TraceOptions;
Expand Down Expand Up @@ -76,7 +76,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
RpcErrorType.INVALID_TRANSACTION_TRACE_PARAMS,
e);
}
final DebugTraceTransactionResult debugTraceTransactionResult =
final DebugTraceTransactionDetails debugTraceTransactionResult =
debugTraceTransactionResult(hash, transactionWithMetadata.get(), traceOptions);

return new JsonRpcSuccessResponse(
Expand All @@ -86,7 +86,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
}
}

private DebugTraceTransactionResult debugTraceTransactionResult(
private DebugTraceTransactionDetails debugTraceTransactionResult(
final Hash hash,
final TransactionWithMetadata transactionWithMetadata,
final TraceOptions traceOptions) {
Expand All @@ -100,7 +100,7 @@ private DebugTraceTransactionResult debugTraceTransactionResult(
mutableWorldState ->
transactionTracer
.traceTransaction(mutableWorldState, blockHash, hash, execTracer)
.map(DebugTraceTransactionResult::new))
.map(DebugTraceTransactionDetails::new))
.orElse(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright contributors to Besu.
*
* 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.api.jsonrpc.internal.processor.TransactionTrace;
import org.hyperledger.besu.ethereum.debug.TraceFrame;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({"gas", "failed", "returnValue", "structLogs"})
public class DebugTraceTransactionDetails {

private final List<StructLog> structLogs;
private final String returnValue;
private final long gas;
private final boolean failed;

public DebugTraceTransactionDetails(final TransactionTrace transactionTrace) {
gas = transactionTrace.getGas();
returnValue = transactionTrace.getResult().getOutput().toString().substring(2);
structLogs = new ArrayList<>(transactionTrace.getTraceFrames().size());
transactionTrace.getTraceFrames().parallelStream()
.map(DebugTraceTransactionDetails::createStructLog)
.forEachOrdered(structLogs::add);
failed = !transactionTrace.getResult().isSuccessful();
}

public static Collection<DebugTraceTransactionResult> of(
final Collection<TransactionTrace> traces) {
return traces.stream().map(DebugTraceTransactionResult::new).collect(Collectors.toList());
}

private static StructLog createStructLog(final TraceFrame frame) {
return frame
.getExceptionalHaltReason()
.map(__ -> (StructLog) new StructLogWithError(frame))
.orElse(new StructLog(frame));
}

@JsonGetter(value = "structLogs")
public List<StructLog> getStructLogs() {
return structLogs;
}

@JsonGetter(value = "returnValue")
public String getReturnValue() {
return returnValue;
}

@JsonGetter(value = "gas")
public long getGas() {
return gas;
}

@JsonGetter(value = "failed")
public boolean failed() {
return failed;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* Copyright contributors to Besu.
*
* 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
Expand All @@ -15,63 +15,37 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;

import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
import org.hyperledger.besu.ethereum.debug.TraceFrame;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({"gas", "failed", "returnValue", "structLogs"})
@JsonPropertyOrder({"txHash", "result"})
public class DebugTraceTransactionResult {

private final List<StructLog> structLogs;
private final String returnValue;
private final long gas;
private final boolean failed;
private final String txHash;

private final DebugTraceTransactionDetails result;

public DebugTraceTransactionResult(final TransactionTrace transactionTrace) {
gas = transactionTrace.getGas();
returnValue = transactionTrace.getResult().getOutput().toString().substring(2);
structLogs = new ArrayList<>(transactionTrace.getTraceFrames().size());
transactionTrace.getTraceFrames().parallelStream()
.map(DebugTraceTransactionResult::createStructLog)
.forEachOrdered(structLogs::add);
failed = !transactionTrace.getResult().isSuccessful();
this.txHash = transactionTrace.getTransaction().getHash().toHexString();
this.result = new DebugTraceTransactionDetails(transactionTrace);
}

public static Collection<DebugTraceTransactionResult> of(
final Collection<TransactionTrace> traces) {
return traces.stream().map(DebugTraceTransactionResult::new).collect(Collectors.toList());
}

private static StructLog createStructLog(final TraceFrame frame) {
return frame
.getExceptionalHaltReason()
.map(__ -> (StructLog) new StructLogWithError(frame))
.orElse(new StructLog(frame));
}

@JsonGetter(value = "structLogs")
public List<StructLog> getStructLogs() {
return structLogs;
}

@JsonGetter(value = "returnValue")
public String getReturnValue() {
return returnValue;
}

@JsonGetter(value = "gas")
public long getGas() {
return gas;
@JsonGetter(value = "txHash")
public String getTxHash() {
return txHash;
}

@JsonGetter(value = "failed")
public boolean failed() {
return failed;
@JsonGetter(value = "result")
public DebugTraceTransactionDetails getResult() {
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat sto
}

public static Object[][] specs() {
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"debug/trace-call"});
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(
new String[] {"debug/trace-call", "debug/trace-block"});
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat sto
}

public static Object[][] specs() {
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"debug/trace-call"});
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(
new String[] {"debug/trace-call", "debug/trace-block"});
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer;
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.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionDetails;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Block;
Expand Down Expand Up @@ -90,10 +90,10 @@ public void shouldReturnCorrectResponse() {
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
when(blockchain.getBlockByHash(block.getHash())).thenReturn(Optional.of(block));

DebugTraceTransactionResult result1 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionResult result2 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionDetails result1 = mock(DebugTraceTransactionDetails.class);
DebugTraceTransactionDetails result2 = mock(DebugTraceTransactionDetails.class);

List<DebugTraceTransactionResult> resultList = Arrays.asList(result1, result2);
List<DebugTraceTransactionDetails> resultList = Arrays.asList(result1, result2);

try (MockedStatic<Tracer> mockedTracer = mockStatic(Tracer.class)) {
mockedTracer
Expand All @@ -109,16 +109,17 @@ public void shouldReturnCorrectResponse() {
assertThat(jsonRpcResponse).isInstanceOf(JsonRpcSuccessResponse.class);
JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) jsonRpcResponse;

final Collection<DebugTraceTransactionResult> traceResult = getResult(response);
final Collection<DebugTraceTransactionDetails> traceResult = getResult(response);
assertThat(traceResult).isNotEmpty();
assertThat(traceResult).isInstanceOf(Collection.class).hasSize(2);
assertThat(traceResult).containsExactly(result1, result2);
}
}

@SuppressWarnings("unchecked")
private Collection<DebugTraceTransactionResult> getResult(final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionResult>) response.getResult();
private Collection<DebugTraceTransactionDetails> getResult(
final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionDetails>) response.getResult();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer;
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.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionDetails;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Block;
Expand Down Expand Up @@ -88,10 +88,10 @@ public void shouldReturnCorrectResponse() {
when(blockchain.getBlockByNumber(blockNumber)).thenReturn(Optional.of(block));
when(block.getHeader()).thenReturn(blockHeader);

DebugTraceTransactionResult result1 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionResult result2 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionDetails result1 = mock(DebugTraceTransactionDetails.class);
DebugTraceTransactionDetails result2 = mock(DebugTraceTransactionDetails.class);

List<DebugTraceTransactionResult> resultList = Arrays.asList(result1, result2);
List<DebugTraceTransactionDetails> resultList = Arrays.asList(result1, result2);

try (MockedStatic<Tracer> mockedTracer = mockStatic(Tracer.class)) {
mockedTracer
Expand All @@ -105,16 +105,17 @@ public void shouldReturnCorrectResponse() {
assertThat(jsonRpcResponse).isInstanceOf(JsonRpcSuccessResponse.class);
JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) jsonRpcResponse;

final Collection<DebugTraceTransactionResult> traceResult = getResult(response);
final Collection<DebugTraceTransactionDetails> traceResult = getResult(response);
assertThat(traceResult).isNotEmpty();
assertThat(traceResult).isInstanceOf(Collection.class).hasSize(2);
assertThat(traceResult).containsExactly(result1, result2);
}
}

@SuppressWarnings("unchecked")
private Collection<DebugTraceTransactionResult> getResult(final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionResult>) response.getResult();
private Collection<DebugTraceTransactionDetails> getResult(
final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionDetails>) response.getResult();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionDetails;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
Expand Down Expand Up @@ -144,10 +144,10 @@ public void shouldReturnCorrectResponse() {
when(blockchain.getBlockByHash(block.getHeader().getParentHash()))
.thenReturn(Optional.of(parentBlock));

DebugTraceTransactionResult result1 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionResult result2 = mock(DebugTraceTransactionResult.class);
DebugTraceTransactionDetails result1 = mock(DebugTraceTransactionDetails.class);
DebugTraceTransactionDetails result2 = mock(DebugTraceTransactionDetails.class);

List<DebugTraceTransactionResult> resultList = Arrays.asList(result1, result2);
List<DebugTraceTransactionDetails> resultList = Arrays.asList(result1, result2);

try (MockedStatic<Tracer> mockedTracer = mockStatic(Tracer.class)) {
mockedTracer
Expand All @@ -163,16 +163,17 @@ public void shouldReturnCorrectResponse() {
assertThat(jsonRpcResponse).isInstanceOf(JsonRpcSuccessResponse.class);
JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) jsonRpcResponse;

final Collection<DebugTraceTransactionResult> traceResult = getResult(response);
final Collection<DebugTraceTransactionDetails> traceResult = getResult(response);
assertThat(traceResult).isNotEmpty();
assertThat(traceResult).isInstanceOf(Collection.class).hasSize(2);
assertThat(traceResult).containsExactly(result1, result2);
}
}

@SuppressWarnings("unchecked")
private Collection<DebugTraceTransactionResult> getResult(final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionResult>) response.getResult();
private Collection<DebugTraceTransactionDetails> getResult(
final JsonRpcSuccessResponse response) {
return (Collection<DebugTraceTransactionDetails>) response.getResult();
}

@Test
Expand Down
Loading
Loading