From e3037c07fd1fef83c7dff968f194d1ea07d9772f Mon Sep 17 00:00:00 2001 From: Angel Soto Date: Tue, 26 Nov 2024 19:14:27 +0100 Subject: [PATCH] Adding withLogs parameter --- .../rsk/rpc/modules/debug/TraceOptions.java | 26 +------ .../trace/call/CallTraceTransformer.java | 74 +++++++++++++------ .../modules/debug/trace/call/CallTracer.java | 15 ++-- .../debug/trace/call/LogInfoResult.java | 44 +++++++++++ .../debug/trace/call/TxTraceResult.java | 16 ++-- 5 files changed, 111 insertions(+), 64 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/LogInfoResult.java diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/TraceOptions.java b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/TraceOptions.java index 819dd6da0f..b6814b1c05 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/TraceOptions.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/TraceOptions.java @@ -19,7 +19,6 @@ package co.rsk.rpc.modules.debug; -import co.rsk.rpc.modules.debug.trace.TracerType; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; @@ -36,8 +35,7 @@ public class TraceOptions { private final Set disabledFields; private final Set unsupportedOptions; private boolean onlyTopCall; - private boolean diffMode; - private TracerType tracerType; + private boolean withLog; public TraceOptions() { this.disabledFields = new HashSet<>(); @@ -55,14 +53,11 @@ public TraceOptions(Map traceOptions) { public final void addOption(String key, String value) { switch (key) { case "onlyTopCall" -> onlyTopCall = Boolean.parseBoolean(value); - case "diffMode" -> diffMode = Boolean.parseBoolean(value); + case "withLog" -> withLog = Boolean.parseBoolean(value); default -> addDisableOption(key, value); } } - - - private void addDisableOption(String key, String value) { DisableOption disableOption = DisableOption.getDisableOption(key); if (disableOption != null) { @@ -74,21 +69,12 @@ private void addDisableOption(String key, String value) { } } - - public void setOnlyTopCall(boolean onlyTopCall) { - this.onlyTopCall = onlyTopCall; - } - - public void setDiffMode(boolean diffMode) { - this.diffMode = diffMode; - } - public boolean isOnlyTopCall() { return onlyTopCall; } - public boolean isDiffMode() { - return diffMode; + public boolean isWithLog() { + return withLog; } public Set getDisabledFields() { @@ -99,10 +85,6 @@ public Set getUnsupportedOptions() { return Collections.unmodifiableSet(unsupportedOptions); } - public TracerType getTracerType() { - return tracerType; - } - public static class Deserializer extends StdDeserializer { @Serial private static final long serialVersionUID = 4222943114560623356L; diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTraceTransformer.java b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTraceTransformer.java index 26ce8ff95e..04825839bf 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTraceTransformer.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTraceTransformer.java @@ -28,18 +28,21 @@ import org.bouncycastle.util.encoders.Hex; import org.ethereum.db.TransactionInfo; import org.ethereum.vm.DataWord; +import org.ethereum.vm.LogInfo; import org.ethereum.vm.program.ProgramResult; import org.ethereum.vm.program.invoke.InvokeData; import org.ethereum.vm.trace.SummarizedProgramTrace; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; public class CallTraceTransformer { private CallTraceTransformer() { } - public static TransactionTrace toTrace(SummarizedProgramTrace trace, TransactionInfo txInfo, DataWord codeAddress, boolean onlyTopCall) { + public static TransactionTrace toTrace(SummarizedProgramTrace trace, TransactionInfo txInfo, DataWord codeAddress, boolean onlyTopCall, boolean withLog) { boolean isContractCreation = txInfo.getReceipt().getTransaction().isContractCreation(); CallType callType = isContractCreation ? CallType.NONE : CallType.CALL; @@ -49,6 +52,11 @@ public static TransactionTrace toTrace(SummarizedProgramTrace trace, Transaction if (trace.getReverted()) { programResult.setRevert(); } + + if (withLog) { + programResult.addLogInfos(txInfo.getReceipt().getLogInfoList()); + } + InvokeData invoke = trace.getInvokeData(); CreationData creationData = null; @@ -64,41 +72,48 @@ public static TransactionTrace toTrace(SummarizedProgramTrace trace, Transaction traceType = TraceType.CREATE; } - TxTraceResult traceOutput = toTrace(traceType, callType, invoke, codeAddress, programResult, creationData); - if(!onlyTopCall) { + TxTraceResult traceOutput = toTrace(traceType, callType, invoke, codeAddress, programResult, creationData, withLog); + if (!onlyTopCall) { for (ProgramSubtrace subtrace : trace.getSubtraces()) { - traceOutput.addCall(toTrace(subtrace)); + traceOutput.addCall(toTrace(subtrace, withLog)); } } return new TransactionTrace(txInfo.getReceipt().getTransaction().getHash().toHexString(), traceOutput); } - private static TxTraceResult toTrace(ProgramSubtrace programSubtrace) { + private static TxTraceResult toTrace(ProgramSubtrace programSubtrace, boolean withLog) { InvokeData invokeData = programSubtrace.getInvokeData(); - TxTraceResult subTrace = toTrace(programSubtrace.getTraceType(), programSubtrace.getCallType(), invokeData, programSubtrace.getCodeAddress(), programSubtrace.getProgramResult(), programSubtrace.getCreationData()); + TxTraceResult subTrace = toTrace(programSubtrace.getTraceType(), programSubtrace.getCallType(), invokeData, programSubtrace.getCodeAddress(), programSubtrace.getProgramResult(), programSubtrace.getCreationData(), withLog); for (ProgramSubtrace call : programSubtrace.getSubtraces()) { - subTrace.addCall(toTrace(call)); + subTrace.addCall(toTrace(call, withLog)); } return subTrace; } - private static TxTraceResult toTrace(TraceType traceType, CallType callType, InvokeData invoke, DataWord codeAddress, ProgramResult programResult, CreationData creationData) { + private static TxTraceResult toTrace(TraceType traceType, CallType callType, InvokeData invoke, DataWord codeAddress, ProgramResult programResult, CreationData creationData, boolean withLog) { String type = traceType == TraceType.CREATE ? "CREATE" : callType.name(); String from; + String to = null; + String gas = null; + //TODO input data is missing in TransferInvoke + String input = null; + String value = null; + String output = null; + String gasUsed = null; + String revertReason = null; + String error = null; + + if (callType == CallType.DELEGATECALL) { from = new RskAddress(invoke.getOwnerAddress().getLast20Bytes()).toJsonString(); } else { from = new RskAddress(invoke.getCallerAddress().getLast20Bytes()).toJsonString(); } - String to = null; - String gas = null; + + List logInfoResultList = null; DataWord callValue = invoke.getCallValue(); - //TODO input data is missing in TransferInvoke - String input = null; - String value = null; - String output = null; if (traceType == TraceType.CREATE) { @@ -125,16 +140,10 @@ private static TxTraceResult toTrace(TraceType traceType, CallType callType, Inv } gas = HexUtils.toQuantityJsonHex(invoke.getGas()); - } - String gasUsed = null; - - String revertReason = null; - String error = null; - if (programResult != null) { gasUsed = HexUtils.toQuantityJsonHex(programResult.getGasUsed()); @@ -142,7 +151,6 @@ private static TxTraceResult toTrace(TraceType traceType, CallType callType, Inv Pair programRevert = EthModule.decodeProgramRevert(programResult); revertReason = programRevert.getLeft(); output = HexUtils.toJsonHex(programRevert.getRight()); - error = "execution reverted"; } else if (traceType != TraceType.CREATE) { output = HexUtils.toJsonHex(programResult.getHReturn()); @@ -152,6 +160,18 @@ private static TxTraceResult toTrace(TraceType traceType, CallType callType, Inv } } + if(withLog) { + logInfoResultList = new ArrayList<>(); + List logInfoList = programResult.getLogInfoList(); + if(logInfoList != null) { + for (int i = 0; i < programResult.getLogInfoList().size(); i++) { + LogInfo logInfo = programResult.getLogInfoList().get(i); + LogInfoResult logInfoResult = fromLogInfo(logInfo, i); + logInfoResultList.add(logInfoResult); + } + } + } + return TxTraceResult.builder() .type(type) .from(from) @@ -163,8 +183,20 @@ private static TxTraceResult toTrace(TraceType traceType, CallType callType, Inv .output(output) .revertReason(revertReason) .error(error) + .logs(logInfoResultList) .build(); } + private static LogInfoResult fromLogInfo(LogInfo logInfo, int index) { + String address = HexUtils.toJsonHex(logInfo.getAddress()); + List topics = logInfo.getTopics().stream().map(DataWord::getData).map(HexUtils::toJsonHex).toList(); + String data = HexUtils.toJsonHex(logInfo.getData()); + return LogInfoResult.builder() + .index(index) + .address(address) + .topics(topics) + .data(data) + .build(); + } } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTracer.java b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTracer.java index e5efe27852..53b33cf5a1 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTracer.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/CallTracer.java @@ -46,8 +46,6 @@ import java.util.List; public class CallTracer implements DebugTracer { - - public static final String UNSUPPORTED_OPERATION = "Operation not supported by this tracer."; private static final Logger logger = LoggerFactory.getLogger("callTracer"); private static final ObjectMapper OBJECT_MAPPER = Serializers.createMapper(true); @@ -93,7 +91,7 @@ public JsonNode traceTransaction(@Nonnull String transactionHash, @Nonnull Trace return null; } - TransactionTrace trace = CallTraceTransformer.toTrace(programTrace, txInfo, null, traceOptions.isOnlyTopCall()); + TransactionTrace trace = CallTraceTransformer.toTrace(programTrace, txInfo, null, traceOptions.isOnlyTopCall(), traceOptions.isWithLog()); return OBJECT_MAPPER.valueToTree(trace.getResult()); } @@ -128,15 +126,12 @@ public TracerType getTracerType() { return TracerType.CALL_TRACER; } - private JsonNode traceBlock(Block block, TraceOptions traceOptions) { - if (traceOptions != null) { - logger.warn("Trace Options not supported yet"); - } - List result = buildBlockTraces(block, traceOptions.isOnlyTopCall()); + private JsonNode traceBlock(Block block, @Nonnull TraceOptions traceOptions) { + List result = buildBlockTraces(block, traceOptions.isOnlyTopCall(), traceOptions.isWithLog()); return OBJECT_MAPPER.valueToTree(result); } - private List buildBlockTraces(Block block, boolean onlyTopCall) { + private List buildBlockTraces(Block block, boolean onlyTopCall, boolean withLog) { List blockTraces = new ArrayList<>(); if (block != null && block.getNumber() != 0) { @@ -161,7 +156,7 @@ private List buildBlockTraces(Block block, boolean onlyTopCall return Collections.emptyList(); } - TransactionTrace trace = CallTraceTransformer.toTrace(programTrace, txInfo, null, onlyTopCall); + TransactionTrace trace = CallTraceTransformer.toTrace(programTrace, txInfo, null, onlyTopCall, withLog); blockTraces.add(trace); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/LogInfoResult.java b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/LogInfoResult.java new file mode 100644 index 0000000000..25aa6f8f01 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/LogInfoResult.java @@ -0,0 +1,44 @@ +package co.rsk.rpc.modules.debug.trace.call; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public record LogInfoResult(@JsonProperty int index, @JsonProperty String address, @JsonProperty List topics, + @JsonProperty String data) { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private int index; + private String address; + private List topics; + private String data; + + public Builder index(int index) { + this.index = index; + return this; + } + + public Builder address(String address) { + this.address = address; + return this; + } + + public Builder topics(List topics) { + this.topics = topics; + return this; + } + + public Builder data(String data) { + this.data = data; + return this; + } + + public LogInfoResult build() { + return new LogInfoResult(index, address, topics, data); + } + } +} diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/TxTraceResult.java b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/TxTraceResult.java index 1b313ed324..95eea86073 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/TxTraceResult.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/debug/trace/call/TxTraceResult.java @@ -38,9 +38,9 @@ public class TxTraceResult { private final String error; private final String revertReason; private final List calls; - private final List logs; + private final List logs; - public TxTraceResult(String type, String from, String to, String value, String gas, String gasUsed, String input, String output, String error, String revertReason, List calls, List logs) { + public TxTraceResult(String type, String from, String to, String value, String gas, String gasUsed, String input, String output, String error, String revertReason, List calls, List logs) { this.type = type; this.from = from; this.to = to; @@ -110,9 +110,8 @@ public List getCalls() { return calls.isEmpty() ? null : calls; } - //TODO @JsonGetter("logs") - public List getLogs() { + public List getLogs() { return logs.isEmpty() ? null : logs; } @@ -125,11 +124,6 @@ public void addCall(TxTraceResult call) { calls.add(call); } - public void addAllCall(List calls) { - this.calls.addAll(calls); - } - - //Builder class public static class Builder { private String type; @@ -143,7 +137,7 @@ public static class Builder { private String error; private String revertReason; private List calls; - private List logs; + private List logs; public Builder type(String type) { this.type = type; @@ -200,7 +194,7 @@ public Builder calls(List calls) { return this; } - public Builder logs(List logs) { + public Builder logs(List logs) { this.logs = logs; return this; }