Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -97,20 +97,29 @@ default Set<String> opcodes() {
* @return TraceOptions object containing the tracer type and configuration.
*/
default TraceOptions traceOptions() {
var defaultTracerConfig =
OpCodeTracerConfigBuilder.createFrom(OpCodeTracerConfig.DEFAULT)
.traceStorage(!disableStorage())
.traceMemory(!disableMemory())
.traceStack(!disableStack())
.traceOpcodes(opcodes())
.build();

// Convert string tracer to TracerType enum, handling null case
TracerType tracerType =
tracer() != null
? TracerType.fromString(tracer())
: TracerType.OPCODE_TRACER; // Default to opcode tracer when null

var builder = OpCodeTracerConfigBuilder.createFrom(OpCodeTracerConfig.DEFAULT);
// Only override defaults when the user explicitly provided a value
if (disableStorageNullable() != null) {
builder.traceStorage(!disableStorage());
}
if (disableMemoryNullable() != null) {
builder.traceMemory(!disableMemory());
} else if (tracerType != TracerType.OPCODE_TRACER) {
// Non-opcode tracers (e.g. callTracer) need memory capture enabled for internal
// operations such as extracting CREATE init code, even when disableMemory is not set
builder.traceMemory(true);
}
if (disableStackNullable() != null) {
builder.traceStack(!disableStack());
}
var defaultTracerConfig = builder.traceOpcodes(opcodes()).build();
Copy link
Member

Choose a reason for hiding this comment

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

nit: I know this was like this before but this name defaultTracerConfig could be misleading. At this stage these option are not default anymore, they are a mix of user set params and defaults, so probably would just call it tracerConfig


return new TraceOptions(tracerType, defaultTracerConfig, tracerConfig(), stateOverrides());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright contributors to Hyperledger 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.parameters;

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.evm.tracing.OpCodeTracerConfigBuilder.OpCodeTracerConfig;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;

public class TransactionTraceParamsTest {

private static final ObjectMapper MAPPER = new ObjectMapper();

@Test
public void emptyOptionsObjectShouldMatchDefaultTraceOptions() throws Exception {
// Passing {} should be equivalent to passing no options at all.
// All disable* fields default to false, so all tracing is enabled by default.
final OpCodeTracerConfig defaultConfig = TraceOptions.DEFAULT.opCodeTracerConfig();

// Parse an empty JSON options object — simulates debug_traceTransaction(hash, {})
final TransactionTraceParams emptyParams = MAPPER.readValue("{}", TransactionTraceParams.class);
final OpCodeTracerConfig emptyParamsConfig = emptyParams.traceOptions().opCodeTracerConfig();

assertThat(emptyParamsConfig.traceMemory())
.describedAs("traceMemory should match DEFAULT")
.isEqualTo(defaultConfig.traceMemory());

assertThat(emptyParamsConfig.traceStorage())
.describedAs("traceStorage should match DEFAULT")
.isEqualTo(defaultConfig.traceStorage());

assertThat(emptyParamsConfig.traceStack())
.describedAs("traceStack should match DEFAULT")
.isEqualTo(defaultConfig.traceStack());
}

@Test
public void defaultsShouldMatchOpCodeTracerConfigDefaults() {
// TraceOptions.DEFAULT should use OpCodeTracerConfig.DEFAULT directly.
// Memory tracing is off by default for performance reasons.
final OpCodeTracerConfig defaultConfig = TraceOptions.DEFAULT.opCodeTracerConfig();

assertThat(defaultConfig.traceStorage()).isTrue();
assertThat(defaultConfig.traceMemory()).isFalse();
assertThat(defaultConfig.traceStack()).isTrue();
}

@Test
public void nonOpcodeTracerShouldEnableMemoryByDefault() throws Exception {
// Non-opcode tracers (e.g. callTracer) need memory for internal operations
// such as extracting CREATE init code, so memory should be enabled by default
final TransactionTraceParams callTracerParams =
MAPPER.readValue("{\"tracer\": \"callTracer\"}", TransactionTraceParams.class);
final OpCodeTracerConfig config = callTracerParams.traceOptions().opCodeTracerConfig();

assertThat(config.traceMemory())
.describedAs("callTracer should have memory enabled by default")
.isTrue();
}

@Test
public void nonOpcodeTracerShouldRespectExplicitDisableMemory() throws Exception {
// When user explicitly sets disableMemory, it should be respected even for callTracer
final TransactionTraceParams params =
MAPPER.readValue(
"{\"tracer\": \"callTracer\", \"disableMemory\": true}", TransactionTraceParams.class);
final OpCodeTracerConfig config = params.traceOptions().opCodeTracerConfig();

assertThat(config.traceMemory())
.describedAs("explicit disableMemory=true should be respected")
.isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,70 +85,49 @@
"op":"CALLDATACOPY",
"gas":16755887,
"gasCost":9,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":14,
"op":"PUSH1",
"gas":16755878,
"gasCost":3,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":16,
"op":"CALLVALUE",
"gas":16755875,
"gasCost":2,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":17,
"op":"PUSH1",
"gas":16755873,
"gasCost":3,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":19,
"op":"CALLDATALOAD",
"gas":16755870,
"gasCost":3,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":20,
"op":"GAS",
"gas":16755867,
"gasCost":2,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":21,
"op":"CALLCODE",
"gas":16755865,
"gasCost":16494066,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000001"
]
"depth":1
},
{
"pc":0,
Expand Down Expand Up @@ -190,70 +169,49 @@
"op":"MSTORE",
"gas":16493351,
"gasCost":6,
"depth":2,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":2
},
{
"pc":9,
"op":"PUSH1",
"gas":16493345,
"gasCost":3,
"depth":2,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":2
},
{
"pc":11,
"op":"PUSH1",
"gas":16493342,
"gasCost":3,
"depth":2,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":2
},
{
"pc":13,
"op":"RETURN",
"gas":16493339,
"gasCost":0,
"depth":2,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":2
},
{
"pc":22,
"op":"PUSH1",
"gas":16755138,
"gasCost":3,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":1
},
{
"pc":24,
"op":"PUSH1",
"gas":16755135,
"gasCost":3,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":1
},
{
"pc":26,
"op":"RETURN",
"gas":16755132,
"gasCost":0,
"depth":1,
"memory":[
"0xf000000000000000000000000000000000000000000000000000000000000002"
]
"depth":1
}
]
}
Expand Down
Loading