Better tracing alignment (#6525)

Update tracing and evm tool
* Intrinsic gas is optional in EVMTool
* For call series, also charge the gas given to the next call level for debug_ series calls.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
pull/6584/head
Danno Ferrin 9 months ago committed by GitHub
parent 24f92019ed
commit 44c80523e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 25
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractTraceByHash.java
  3. 15
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractTraceCall.java
  4. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugAccountAt.java
  5. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlock.java
  6. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByHash.java
  7. 16
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockByNumber.java
  8. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java
  9. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceTransaction.java
  10. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java
  11. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java
  12. 9
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCallMany.java
  13. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceFilter.java
  14. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceRawTransaction.java
  15. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceReplayBlockTransactions.java
  16. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_all.json
  17. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_complete.json
  18. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableMemory.json
  19. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableStack.json
  20. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableStorage.json
  21. 4
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java
  22. 27
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java
  23. 57
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java
  24. 82
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  25. 2
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/all-trace-flags-disabled.json
  26. 2
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/all-trace-flags.json
  27. 2
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/no-memory.json
  28. 6
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/badcode.json
  29. 75
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/charge-intrinsic.json
  30. 46
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-cold.json
  31. 46
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-warm.json
  32. 12
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/revert.json
  33. 72
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/warm-contract.json
  34. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java
  35. 7
      evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java
  36. 12
      evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java

@ -48,6 +48,7 @@
- Fix the way an advertised host configured with `--p2p-host` is treated when communicating with the originator of a PING packet [#6225](https://github.com/hyperledger/besu/pull/6225)
- Fix `poa-block-txs-selection-max-time` option that was inadvertently reset to its default after being configured [#6444](https://github.com/hyperledger/besu/pull/6444)
- Fix for tx incorrectly discarded when there is a timeout during block creation [#6563](https://github.com/hyperledger/besu/pull/6563)
- Fix traces so that call gas costing in traces matches other clients traces [#6525](https://github.com/hyperledger/besu/pull/6525)
### Download Links

@ -78,19 +78,18 @@ public abstract class AbstractTraceByHash implements JsonRpcMethod {
return Tracer.processTracing(
blockchainQueries,
Optional.of(block.getHeader()),
mutableWorldState -> {
return blockTracerSupplier
.get()
.trace(
mutableWorldState,
block,
new DebugOperationTracer(new TraceOptions(false, false, true)))
.map(BlockTrace::getTransactionTraces)
.orElse(Collections.emptyList())
.stream()
.filter(trxTrace -> trxTrace.getTransaction().getHash().equals(transactionHash))
.findFirst();
})
mutableWorldState ->
blockTracerSupplier
.get()
.trace(
mutableWorldState,
block,
new DebugOperationTracer(new TraceOptions(false, false, true), false))
.map(BlockTrace::getTransactionTraces)
.orElse(Collections.emptyList())
.stream()
.filter(trxTrace -> trxTrace.getTransaction().getHash().equals(transactionHash))
.findFirst())
.orElseThrow();
}

@ -36,11 +36,20 @@ import org.slf4j.LoggerFactory;
public abstract class AbstractTraceCall extends AbstractTraceByBlock {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTraceCall.class);
public AbstractTraceCall(
/**
* A flag to indicate if call operations should trace just the operation cost (false, Geth style,
* debug_ series RPCs) or the operation cost and all gas granted to the child call (true, Parity
* style, trace_ series RPCs)
*/
private final boolean recordChildCallGas;
protected AbstractTraceCall(
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator) {
final TransactionSimulator transactionSimulator,
final boolean recordChildCallGas) {
super(blockchainQueries, protocolSchedule, transactionSimulator);
this.recordChildCallGas = recordChildCallGas;
}
@Override
@ -65,7 +74,7 @@ public abstract class AbstractTraceCall extends AbstractTraceByBlock {
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), BLOCK_NOT_FOUND);
}
final DebugOperationTracer tracer = new DebugOperationTracer(traceOptions);
final DebugOperationTracer tracer = new DebugOperationTracer(traceOptions, recordChildCallGas);
return transactionSimulator
.process(
callParams,

@ -98,7 +98,7 @@ public class DebugAccountAt extends AbstractBlockParameterOrBlockHashMethod {
.trace(
mutableWorldState,
blockHash,
new DebugOperationTracer(new TraceOptions(false, true, true)))
new DebugOperationTracer(new TraceOptions(false, true, true), false))
.map(BlockTrace::getTransactionTraces)
.orElse(Collections.emptyList())
.stream()

@ -87,7 +87,10 @@ public class DebugTraceBlock implements JsonRpcMethod {
mutableWorldState ->
blockTracerSupplier
.get()
.trace(mutableWorldState, block, new DebugOperationTracer(traceOptions))
.trace(
mutableWorldState,
block,
new DebugOperationTracer(traceOptions, true))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of))
.orElse(null);

@ -64,7 +64,10 @@ public class DebugTraceBlockByHash implements JsonRpcMethod {
mutableWorldState ->
blockTracerSupplier
.get()
.trace(mutableWorldState, blockHash, new DebugOperationTracer(traceOptions))
.trace(
mutableWorldState,
blockHash,
new DebugOperationTracer(traceOptions, true))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of))
.orElse(null);

@ -66,13 +66,15 @@ public class DebugTraceBlockByNumber extends AbstractBlockParameterMethod {
Tracer.processTracing(
blockchainQueriesSupplier.get(),
hash,
mutableWorldState -> {
return blockTracerSupplier
.get()
.trace(mutableWorldState, hash, new DebugOperationTracer(traceOptions))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of);
}))
mutableWorldState ->
blockTracerSupplier
.get()
.trace(
mutableWorldState,
hash,
new DebugOperationTracer(traceOptions, true))
.map(BlockTrace::getTransactionTraces)
.map(DebugTraceTransactionResult::of)))
.orElse(null);
}
}

@ -43,7 +43,7 @@ public class DebugTraceCall extends AbstractTraceCall {
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator) {
super(blockchainQueries, protocolSchedule, transactionSimulator);
super(blockchainQueries, protocolSchedule, transactionSimulator, true);
}
@Override

@ -73,7 +73,7 @@ public class DebugTraceTransaction implements JsonRpcMethod {
final TraceOptions traceOptions) {
final Hash blockHash = transactionWithMetadata.getBlockHash().get();
final DebugOperationTracer execTracer = new DebugOperationTracer(traceOptions);
final DebugOperationTracer execTracer = new DebugOperationTracer(traceOptions, true);
return Tracer.processTracing(
blockchain,

@ -116,7 +116,7 @@ public class TraceBlock extends AbstractBlockParameterMethod {
"step",
"action");
DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true));
new DebugOperationTracer(new TraceOptions(false, false, true), false);
ExecuteTransactionStep executeTransactionStep =
new ExecuteTransactionStep(
chainUpdater,

@ -41,7 +41,7 @@ public class TraceCall extends AbstractTraceCall {
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator) {
super(blockchainQueries, protocolSchedule, transactionSimulator);
super(blockchainQueries, protocolSchedule, transactionSimulator, false);
}
@Override

@ -66,11 +66,7 @@ public class TraceCallMany extends TraceCall implements JsonRpcMethod {
final Optional<BlockParameter> maybeBlockParameter =
request.getOptionalParameter(1, BlockParameter.class);
if (maybeBlockParameter.isPresent()) {
return maybeBlockParameter.get();
}
return BlockParameter.LATEST;
return maybeBlockParameter.orElse(BlockParameter.LATEST);
}
@Override
@ -153,7 +149,8 @@ public class TraceCallMany extends TraceCall implements JsonRpcMethod {
final BlockHeader header,
final WorldUpdater worldUpdater) {
final Set<TraceTypeParameter.TraceType> traceTypes = traceTypeParameter.getTraceTypes();
final DebugOperationTracer tracer = new DebugOperationTracer(buildTraceOptions(traceTypes));
final DebugOperationTracer tracer =
new DebugOperationTracer(buildTraceOptions(traceTypes), false);
final Optional<TransactionSimulatorResult> maybeSimulatorResult =
transactionSimulator.processWithWorldUpdater(
callParameter, buildTransactionValidationParams(), tracer, header, worldUpdater);

@ -161,7 +161,7 @@ public class TraceFilter extends TraceBlock {
"action");
DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true));
new DebugOperationTracer(new TraceOptions(false, false, true), false);
ExecuteTransactionStep executeTransactionStep =
new ExecuteTransactionStep(
chainUpdater,

@ -89,7 +89,8 @@ public class TraceRawTransaction extends AbstractTraceByBlock implements JsonRpc
}
final Set<TraceTypeParameter.TraceType> traceTypes = traceTypeParameter.getTraceTypes();
final DebugOperationTracer tracer = new DebugOperationTracer(buildTraceOptions(traceTypes));
final DebugOperationTracer tracer =
new DebugOperationTracer(buildTraceOptions(traceTypes), false);
final BlockHeader headBlock = blockchainQueriesSupplier.get().headBlockHeader();
return transactionSimulator
.process(

@ -93,7 +93,7 @@ public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod {
return getBlockchainQueries()
.getBlockchain()
.getBlockByNumber(blockNumber)
.map((block) -> traceBlock(block, traceTypeParameter))
.map(block -> traceBlock(block, traceTypeParameter))
.orElse(null);
}
@ -127,7 +127,7 @@ public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod {
"step",
"action");
final DebugOperationTracer debugOperationTracer =
new DebugOperationTracer(new TraceOptions(false, false, true));
new DebugOperationTracer(new TraceOptions(false, false, true), false);
final ExecuteTransactionStep executeTransactionStep =
new ExecuteTransactionStep(
chainUpdater,

@ -167,7 +167,7 @@
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"gasCost" : 16494066,
"depth" : 1,
"stack" : null,
"memory" : null,

@ -164,7 +164,7 @@
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"gasCost" : 16494066,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],

@ -167,7 +167,7 @@
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"gasCost" : 16494066,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : null,

@ -167,7 +167,7 @@
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"gasCost" : 16494066,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],

@ -167,7 +167,7 @@
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"gasCost" : 16494066,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],

@ -119,7 +119,7 @@ public class TraceTransactionIntegrationTest {
// Now call the transaction to execute the SSTORE.
final DebugOperationTracer tracer =
new DebugOperationTracer(new TraceOptions(true, true, true));
new DebugOperationTracer(new TraceOptions(true, true, true), false);
final Transaction executeTransaction =
Transaction.builder()
.type(TransactionType.FRONTIER)
@ -166,7 +166,7 @@ public class TraceTransactionIntegrationTest {
@Test
public void shouldTraceContractCreation() {
final DebugOperationTracer tracer =
new DebugOperationTracer(new TraceOptions(true, true, true));
new DebugOperationTracer(new TraceOptions(true, true, true), false);
final Transaction transaction =
Transaction.readFrom(
new BytesValueRLPInput(Bytes.fromHexString(CONTRACT_CREATION_TX), false));

@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.AbstractCallOperation;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.tracing.OperationTracer;
@ -39,6 +40,14 @@ import org.apache.tuweni.units.bigints.UInt256;
public class DebugOperationTracer implements OperationTracer {
private final TraceOptions options;
/**
* A flag to indicate if call operations should trace just the operation cost (false, Geth style,
* debug_ series RPCs) or the operation cost and all gas granted to the child call (true, Parity
* style, trace_ series RPCs)
*/
private final boolean recordChildCallGas;
private List<TraceFrame> traceFrames = new ArrayList<>();
private TraceFrame lastFrame;
@ -48,8 +57,16 @@ public class DebugOperationTracer implements OperationTracer {
private int pc;
private int depth;
public DebugOperationTracer(final TraceOptions options) {
/**
* Creates the operation tracer.
*
* @param options The options, as passed in through the RPC
* @param recordChildCallGas A flag on whether to produce geth style (true) or parity style
* (false) gas amounts for call operations
*/
public DebugOperationTracer(final TraceOptions options, final boolean recordChildCallGas) {
this.options = options;
this.recordChildCallGas = recordChildCallGas;
}
@Override
@ -78,14 +95,16 @@ public class DebugOperationTracer implements OperationTracer {
final Optional<Map<UInt256, UInt256>> storage = captureStorage(frame);
final Optional<Map<Address, Wei>> maybeRefunds =
frame.getRefunds().isEmpty() ? Optional.empty() : Optional.of(frame.getRefunds());
long thisGasCost = operationResult.getGasCost();
if (recordChildCallGas && currentOperation instanceof AbstractCallOperation) {
thisGasCost += frame.getMessageFrameStack().getFirst().getRemainingGas();
}
lastFrame =
new TraceFrame(
pc,
Optional.of(opcode),
gasRemaining,
operationResult.getGasCost() == 0
? OptionalLong.empty()
: OptionalLong.of(operationResult.getGasCost()),
thisGasCost == 0 ? OptionalLong.empty() : OptionalLong.of(thisGasCost),
frame.getGasRefund(),
depth,
Optional.ofNullable(operationResult.getHaltReason()),

@ -29,12 +29,15 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.operation.AbstractOperation;
import org.hyperledger.besu.evm.operation.CallOperation;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Map;
import java.util.OptionalLong;
import java.util.TreeMap;
import org.apache.tuweni.bytes.Bytes32;
@ -63,6 +66,8 @@ class DebugOperationTracerTest {
}
};
private final CallOperation callOperation = new CallOperation(new CancunGasCalculator());
@Test
void shouldRecordProgramCounter() {
final MessageFrame frame = validMessageFrame();
@ -108,7 +113,7 @@ class DebugOperationTracerTest {
frame.pushStackItem(stackItem1);
frame.pushStackItem(stackItem2);
frame.pushStackItem(stackItem3);
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, false, true));
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, false, true), false);
assertThat(traceFrame.getStack()).isPresent();
assertThat(traceFrame.getStack().get()).containsExactly(stackItem1, stackItem2, stackItem3);
}
@ -116,7 +121,7 @@ class DebugOperationTracerTest {
@Test
void shouldNotRecordStackWhenDisabled() {
final TraceFrame traceFrame =
traceFrame(validMessageFrame(), new TraceOptions(false, false, false));
traceFrame(validMessageFrame(), new TraceOptions(false, false, false), false);
assertThat(traceFrame.getStack()).isEmpty();
}
@ -129,7 +134,7 @@ class DebugOperationTracerTest {
frame.writeMemory(0, 32, word1);
frame.writeMemory(32, 32, word2);
frame.writeMemory(64, 32, word3);
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, true, false));
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, true, false), false);
assertThat(traceFrame.getMemory()).isPresent();
assertThat(traceFrame.getMemory().get()).containsExactly(word1, word2, word3);
}
@ -137,7 +142,7 @@ class DebugOperationTracerTest {
@Test
void shouldNotRecordMemoryWhenDisabled() {
final TraceFrame traceFrame =
traceFrame(validMessageFrame(), new TraceOptions(false, false, false));
traceFrame(validMessageFrame(), new TraceOptions(false, false, false), false);
assertThat(traceFrame.getMemory()).isEmpty();
}
@ -145,7 +150,7 @@ class DebugOperationTracerTest {
void shouldRecordStorageWhenEnabled() {
final MessageFrame frame = validMessageFrame();
final Map<UInt256, UInt256> updatedStorage = setupStorageForCapture(frame);
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(true, false, false));
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(true, false, false), false);
assertThat(traceFrame.getStorage()).isPresent();
assertThat(traceFrame.getStorage()).contains(updatedStorage);
}
@ -153,17 +158,41 @@ class DebugOperationTracerTest {
@Test
void shouldNotRecordStorageWhenDisabled() {
final TraceFrame traceFrame =
traceFrame(validMessageFrame(), new TraceOptions(false, false, false));
traceFrame(validMessageFrame(), new TraceOptions(false, false, false), false);
assertThat(traceFrame.getStorage()).isEmpty();
}
@Test
void shouldNotAddGasWhenDisabled() {
final TraceFrame traceFrame =
traceFrame(validCallFrame(), new TraceOptions(false, false, false), false);
assertThat(traceFrame.getGasCost()).isEqualTo(OptionalLong.of(20));
}
@Test
void shouldAddGasWhenEnabled() {
final TraceFrame traceFrame =
traceFrame(validCallFrame(), new TraceOptions(false, false, false), true);
assertThat(traceFrame.getGasCost()).isEqualTo(OptionalLong.of(1020L));
}
@Test
void childGasFlagDoesNotMatterForNonCallOperations() {
final TraceFrame flagDisabledTracer =
traceFrame(validMessageFrame(), new TraceOptions(false, false, false), false);
final TraceFrame flagEnabledTracer =
traceFrame(validMessageFrame(), new TraceOptions(false, false, false), true);
assertThat(flagEnabledTracer.getGasCost()).isEqualTo(flagDisabledTracer.getGasCost());
}
@Test
void shouldCaptureFrameWhenExceptionalHaltOccurs() {
final MessageFrame frame = validMessageFrame();
final Map<UInt256, UInt256> updatedStorage = setupStorageForCapture(frame);
final DebugOperationTracer tracer =
new DebugOperationTracer(new TraceOptions(true, true, true));
new DebugOperationTracer(new TraceOptions(true, true, true), false);
tracer.tracePostExecution(
frame, new OperationResult(50L, ExceptionalHaltReason.INSUFFICIENT_GAS));
@ -174,11 +203,12 @@ class DebugOperationTracerTest {
}
private TraceFrame traceFrame(final MessageFrame frame) {
return traceFrame(frame, new TraceOptions(false, false, false));
return traceFrame(frame, new TraceOptions(false, false, false), false);
}
private TraceFrame traceFrame(final MessageFrame frame, final TraceOptions traceOptions) {
final DebugOperationTracer tracer = new DebugOperationTracer(traceOptions);
private TraceFrame traceFrame(
final MessageFrame frame, final TraceOptions traceOptions, final boolean additionalCallGas) {
final DebugOperationTracer tracer = new DebugOperationTracer(traceOptions, additionalCallGas);
tracer.tracePreExecution(frame);
OperationResult operationResult = anOperation.execute(frame, null);
tracer.tracePostExecution(frame, operationResult);
@ -192,6 +222,13 @@ class DebugOperationTracerTest {
return frame;
}
private MessageFrame validCallFrame() {
final MessageFrame frame = validMessageFrameBuilder().build();
frame.setCurrentOperation(callOperation);
frame.setPC(10);
return frame;
}
private TraceFrame getOnlyTraceFrame(final DebugOperationTracer tracer) {
Assertions.assertThat(tracer.getTraceFrames()).hasSize(1);
return tracer.getTraceFrames().get(0);

@ -19,6 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static picocli.CommandLine.ScopeType.INHERIT;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.collections.trie.BytesTrieSet;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
@ -110,6 +111,13 @@ public class EvmToolCommand implements Runnable {
paramLabel = "<int>")
private final Long gas = 10_000_000_000L;
@Option(
names = {"--intrinsic-gas"},
description = "Calculate and charge intrinsic and tx content gas. Default is not to charge.",
scope = INHERIT,
negatable = true)
final Boolean chargeIntrinsicGas = false;
@Option(
names = {"--price"},
description = "Price of gas (in GWei) for this invocation",
@ -326,26 +334,6 @@ public class EvmToolCommand implements Runnable {
.metricsSystemModule(new MetricsSystemModule())
.build();
final BlockHeader blockHeader =
BlockHeaderBuilder.create()
.parentHash(Hash.EMPTY)
.coinbase(coinbase)
.difficulty(Difficulty.ONE)
.number(1)
.gasLimit(5000)
.timestamp(Instant.now().toEpochMilli())
.ommersHash(Hash.EMPTY_LIST_HASH)
.stateRoot(Hash.EMPTY_TRIE_HASH)
.transactionsRoot(Hash.EMPTY)
.receiptsRoot(Hash.EMPTY)
.logsBloom(LogsBloomFilter.empty())
.gasUsed(0)
.extraData(Bytes.EMPTY)
.mixHash(Hash.EMPTY)
.nonce(0)
.blockHeaderFunctions(new MainnetBlockHeaderFunctions())
.buildBlockHeader();
int remainingIters = this.repeat;
final ProtocolSpec protocolSpec =
component.getProtocolSpec().apply(BlockHeaderBuilder.createDefault().buildBlockHeader());
@ -360,15 +348,19 @@ public class EvmToolCommand implements Runnable {
.sender(sender)
.build();
final long intrinsicGasCost =
protocolSpec
.getGasCalculator()
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation());
final long accessListCost =
tx.getAccessList()
.map(list -> protocolSpec.getGasCalculator().accessListGasCost(list))
.orElse(0L);
long txGas = gas - intrinsicGasCost - accessListCost;
long txGas = gas;
if (chargeIntrinsicGas) {
final long intrinsicGasCost =
protocolSpec
.getGasCalculator()
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation());
txGas -= intrinsicGasCost;
final long accessListCost =
tx.getAccessList()
.map(list -> protocolSpec.getGasCalculator().accessListGasCost(list))
.orElse(0L);
txGas -= accessListCost;
}
final EVM evm = protocolSpec.getEvm();
if (codeBytes.isEmpty()) {
@ -395,6 +387,33 @@ public class EvmToolCommand implements Runnable {
var contractAccount = updater.getOrCreate(contract);
contractAccount.setCode(codeBytes);
final Set<Address> addressList = new BytesTrieSet<>(Address.SIZE);
addressList.add(sender);
addressList.add(contract);
if (EvmSpecVersion.SHANGHAI.compareTo(evm.getEvmVersion()) <= 0) {
addressList.add(coinbase);
}
final BlockHeader blockHeader =
BlockHeaderBuilder.create()
.parentHash(Hash.EMPTY)
.coinbase(coinbase)
.difficulty(Difficulty.ONE)
.number(1)
.gasLimit(5000)
.timestamp(Instant.now().toEpochMilli())
.ommersHash(Hash.EMPTY_LIST_HASH)
.stateRoot(Hash.EMPTY_TRIE_HASH)
.transactionsRoot(Hash.EMPTY)
.receiptsRoot(Hash.EMPTY)
.logsBloom(LogsBloomFilter.empty())
.gasUsed(0)
.extraData(Bytes.EMPTY)
.mixHash(Hash.EMPTY)
.nonce(0)
.blockHeaderFunctions(new MainnetBlockHeaderFunctions())
.baseFee(component.getBlockchain().getChainHeadHeader().getBaseFee().orElse(null))
.buildBlockHeader();
MessageFrame initialMessageFrame =
MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL)
@ -414,10 +433,7 @@ public class EvmToolCommand implements Runnable {
.completer(c -> {})
.miningBeneficiary(blockHeader.getCoinbase())
.blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain()))
.accessListWarmAddresses(
EvmSpecVersion.SHANGHAI.compareTo(evm.getEvmVersion()) <= 0
? Set.of(coinbase)
: Set.of())
.accessListWarmAddresses(addressList)
.build();
Deque<MessageFrame> messageFrameStack = initialMessageFrame.getMessageFrameStack();

@ -84,7 +84,7 @@
{"pc":8,"op":96,"gas":"0x9ffffadec","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":115,"gas":"0x9ffffade9","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"PUSH20"},
{"pc":31,"op":100,"gas":"0x9ffffade6","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"PUSH5"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0xa28","memSize":0,"depth":1,"refund":0,"opName":"CALL"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0x900000a28","memSize":0,"depth":1,"refund":0,"opName":"CALL"},
{"pc":0,"op":125,"gas":"0x900000000","gasCost":"0x3","memSize":0,"depth":2,"refund":0,"opName":"PUSH30"},
{"pc":31,"op":96,"gas":"0x8fffffffd","gasCost":"0x3","memSize":0,"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":33,"op":82,"gas":"0x8fffffffa","gasCost":"0x6","memSize":0,"depth":2,"refund":0,"opName":"MSTORE"},

@ -84,7 +84,7 @@
{"pc":8,"op":96,"gas":"0x9ffffadec","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":115,"gas":"0x9ffffade9","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH20"},
{"pc":31,"op":100,"gas":"0x9ffffade6","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6"],"depth":1,"refund":0,"opName":"PUSH5"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0xa28","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6","0x900000000"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0x900000a28","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6","0x900000000"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":0,"op":125,"gas":"0x900000000","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH30"},
{"pc":31,"op":96,"gas":"0x8fffffffd","gasCost":"0x3","memSize":0,"stack":["0x111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":33,"op":82,"gas":"0x8fffffffa","gasCost":"0x6","memSize":0,"stack":["0x111122223333444455556666777788889999aaaabbbbccccddddeeeeffff","0x0"],"depth":2,"refund":0,"opName":"MSTORE"},

@ -82,7 +82,7 @@
{"pc":8,"op":96,"gas":"0x9ffffadec","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":115,"gas":"0x9ffffade9","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH20"},
{"pc":31,"op":100,"gas":"0x9ffffade6","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6"],"depth":1,"refund":0,"opName":"PUSH5"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0xa28","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6","0x900000000"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":37,"op":241,"gas":"0x9ffffade3","gasCost":"0x900000a28","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xaabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6","0x900000000"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":0,"op":125,"gas":"0x900000000","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH30"},
{"pc":31,"op":96,"gas":"0x8fffffffd","gasCost":"0x3","memSize":0,"stack":["0x111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":33,"op":82,"gas":"0x8fffffffa","gasCost":"0x6","memSize":0,"stack":["0x111122223333444455556666777788889999aaaabbbbccccddddeeeeffff","0x0"],"depth":2,"refund":0,"opName":"MSTORE"},

@ -7,8 +7,8 @@
],
"stdin": "",
"stdout": [
{"pc":0,"op":96,"gas":"0x2540b91f8","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":239,"gas":"0x2540b91f5","gasCost":"0x0","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"},
{"gasUser":"0x2540b91f8","gasTotal":"0x2540b91f8","output":"0x"}
{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":239,"gas":"0x2540be3fd","gasCost":"0x0","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"},
{"gasUser":"0x2540be400","gasTotal":"0x2540be400","output":"0x"}
]
}

@ -0,0 +1,75 @@
{
"cli": [
"--notime",
"--json",
"--code",
"60408053604060405560406000604060006000305af16040f3",
"--receiver",
"0xc0de",
"--contract",
"0xc0de",
"--gas",
"46180",
"--input",
"0xbadbadc0de",
"--intrinsic-gas"
],
"stdin": "",
"stdout": [
{"pc":0,"op":96,"gas":"0x620c","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x6209","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x6206","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x61fa","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x61f7","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x61f4","gasCost":"0x5654","memSize":96,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0xba0","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0xb9d","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0xb9a","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0xb97","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0xb94","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0xb91","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":1,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0xb8f","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":1,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0xb8d","gasCost":"0xb61","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0xb8d"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0xafd","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0xafa","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":2,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0xaf7","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":2,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0xaeb","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0xae8","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0xae5","gasCost":"0x64","memSize":96,"stack":["0x40","0x40"],"depth":2,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0xa81","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0xa7e","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0xa7b","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0xa78","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0xa75","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0xa72","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":2,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0xa70","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":2,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0xa6e","gasCost":"0xa46","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0xa6e"],"depth":2,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0x9e2","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x9df","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":3,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x9dc","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":3,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x9d0","gasCost":"0x3","memSize":96,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x9cd","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x9ca","gasCost":"0x64","memSize":96,"stack":["0x40","0x40"],"depth":3,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0x966","gasCost":"0x3","memSize":96,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0x963","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0x960","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0x95d","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0x95a","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0x957","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":3,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0x955","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":3,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0x953","gasCost":"0x930","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0x953"],"depth":3,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0x8cc","gasCost":"0x3","memSize":0,"stack":[],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x8c9","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":4,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x8c6","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":4,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x8ba","gasCost":"0x3","memSize":96,"stack":[],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x8b7","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x8b4","gasCost":"0x8fc","memSize":96,"stack":["0x40","0x40"],"depth":4,"refund":0,"opName":"SSTORE","error":"Out of gas"},
{"pc":22,"op":96,"gas":"0x23","gasCost":"0x3","memSize":96,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x20","gasCost":"0x0","memSize":96,"stack":["0x0","0x40"],"depth":3,"refund":0,"opName":"RETURN"},
{"pc":22,"op":96,"gas":"0x48","gasCost":"0x3","memSize":96,"stack":["0x1"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x45","gasCost":"0x0","memSize":96,"stack":["0x1","0x40"],"depth":2,"refund":0,"opName":"RETURN"},
{"pc":22,"op":96,"gas":"0x71","gasCost":"0x3","memSize":96,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x6e","gasCost":"0x0","memSize":96,"stack":["0x1","0x40"],"depth":1,"refund":0,"opName":"RETURN"},
{"gasUser":"0x619e","gasTotal":"0x619e","output":"0x40"}
]
}

@ -11,47 +11,9 @@
],
"stdin": "",
"stdout": [
{
"pc": 0,
"op": 65,
"gas": "0x2540b91f8",
"gasCost": "0x2",
"memSize": 0,
"stack": [],
"depth": 1,
"refund": 0,
"opName": "COINBASE"
},
{
"pc": 1,
"op": 49,
"gas": "0x2540b91f6",
"gasCost": "0xa28",
"memSize": 0,
"stack": [
"0x4444588443c3a91288c5002483449aba1054192b"
],
"depth": 1,
"refund": 0,
"opName": "BALANCE"
},
{
"pc": 2,
"op": 255,
"gas": "0x2540b87ce",
"gasCost": "0x1388",
"memSize": 0,
"stack": [
"0x0"
],
"depth": 1,
"refund": 0,
"opName": "SELFDESTRUCT"
},
{
"gasUser": "0x1db2",
"gasTotal": "0x1db2",
"output": "0x"
}
{"pc":0,"op":65,"gas":"0x2540be400","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"COINBASE"},
{"pc":1,"op":49,"gas":"0x2540be3fe","gasCost":"0xa28","memSize":0,"stack":["0x4444588443c3a91288c5002483449aba1054192b"],"depth":1,"refund":0,"opName":"BALANCE"},
{"pc":2,"op":255,"gas":"0x2540bd9d6","gasCost":"0x1388","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SELFDESTRUCT"},
{"gasUser":"0x1db2","gasTotal":"0x1db2","output":"0x"}
]
}

@ -11,47 +11,9 @@
],
"stdin": "",
"stdout": [
{
"pc": 0,
"op": 65,
"gas": "0x2540b91f8",
"gasCost": "0x2",
"memSize": 0,
"stack": [],
"depth": 1,
"refund": 0,
"opName": "COINBASE"
},
{
"pc": 1,
"op": 49,
"gas": "0x2540b91f6",
"gasCost": "0x64",
"memSize": 0,
"stack": [
"0x4444588443c3a91288c5002483449aba1054192b"
],
"depth": 1,
"refund": 0,
"opName": "BALANCE"
},
{
"pc": 2,
"op": 255,
"gas": "0x2540b9192",
"gasCost": "0x1388",
"memSize": 0,
"stack": [
"0x0"
],
"depth": 1,
"refund": 0,
"opName": "SELFDESTRUCT"
},
{
"gasUser": "0x13ee",
"gasTotal": "0x13ee",
"output": "0x"
}
{"pc":0,"op":65,"gas":"0x2540be400","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"COINBASE"},
{"pc":1,"op":49,"gas":"0x2540be3fe","gasCost":"0x64","memSize":0,"stack":["0x4444588443c3a91288c5002483449aba1054192b"],"depth":1,"refund":0,"opName":"BALANCE"},
{"pc":2,"op":255,"gas":"0x2540be39a","gasCost":"0x1388","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SELFDESTRUCT"},
{"gasUser":"0x13ee","gasTotal":"0x13ee","output":"0x"}
]
}

@ -7,12 +7,12 @@
],
"stdin": "",
"stdout": [
{"pc":0,"op":99,"gas":"0x2540b91f8","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH4"},
{"pc":5,"op":96,"gas":"0x2540b91f5","gasCost":"0x3","memSize":0,"stack":["0x4e6f7065"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":7,"op":82,"gas":"0x2540b91f2","gasCost":"0x6","memSize":0,"stack":["0x4e6f7065","0x0"],"depth":1,"refund":0,"opName":"MSTORE"},
{"pc":8,"op":96,"gas":"0x2540b91ec","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":96,"gas":"0x2540b91e9","gasCost":"0x3","memSize":32,"stack":["0x4"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":12,"op":253,"gas":"0x2540b91e6","gasCost":"0x0","memSize":32,"stack":["0x4","0x1c"],"depth":1,"refund":0,"opName":"REVERT","error":"Nope"},
{"pc":0,"op":99,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH4"},
{"pc":5,"op":96,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"stack":["0x4e6f7065"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":7,"op":82,"gas":"0x2540be3fa","gasCost":"0x6","memSize":0,"stack":["0x4e6f7065","0x0"],"depth":1,"refund":0,"opName":"MSTORE"},
{"pc":8,"op":96,"gas":"0x2540be3f4","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":10,"op":96,"gas":"0x2540be3f1","gasCost":"0x3","memSize":32,"stack":["0x4"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":12,"op":253,"gas":"0x2540be3ee","gasCost":"0x0","memSize":32,"stack":["0x4","0x1c"],"depth":1,"refund":0,"opName":"REVERT","error":"Nope"},
{"gasUser":"0x12","gasTotal":"0x12","output":"0x4e6f7065"}
]
}

@ -0,0 +1,72 @@
{
"cli": [
"--notime",
"--json",
"--code",
"60408053604060405560406000604060006000305af16040f3",
"--receiver",
"0xc0de",
"--contract",
"0xc0de",
"--gas",
"25100"
],
"stdin": "",
"stdout": [
{"pc":0,"op":96,"gas":"0x620c","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x6209","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x6206","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x61fa","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x61f7","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x61f4","gasCost":"0x5654","memSize":96,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0xba0","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0xb9d","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0xb9a","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0xb97","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0xb94","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0xb91","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":1,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0xb8f","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":1,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0xb8d","gasCost":"0xb61","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0xb8d"],"depth":1,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0xafd","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0xafa","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":2,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0xaf7","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":2,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0xaeb","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0xae8","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0xae5","gasCost":"0x64","memSize":96,"stack":["0x40","0x40"],"depth":2,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0xa81","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0xa7e","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0xa7b","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0xa78","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0xa75","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0xa72","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":2,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0xa70","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":2,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0xa6e","gasCost":"0xa46","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0xa6e"],"depth":2,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0x9e2","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x9df","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":3,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x9dc","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":3,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x9d0","gasCost":"0x3","memSize":96,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x9cd","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x9ca","gasCost":"0x64","memSize":96,"stack":["0x40","0x40"],"depth":3,"refund":0,"opName":"SSTORE"},
{"pc":9,"op":96,"gas":"0x966","gasCost":"0x3","memSize":96,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":11,"op":96,"gas":"0x963","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":13,"op":96,"gas":"0x960","gasCost":"0x3","memSize":96,"stack":["0x40","0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":15,"op":96,"gas":"0x95d","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":17,"op":96,"gas":"0x95a","gasCost":"0x3","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":19,"op":48,"gas":"0x957","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0"],"depth":3,"refund":0,"opName":"ADDRESS"},
{"pc":20,"op":90,"gas":"0x955","gasCost":"0x2","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de"],"depth":3,"refund":0,"opName":"GAS"},
{"pc":21,"op":241,"gas":"0x953","gasCost":"0x930","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x0","0xc0de","0x953"],"depth":3,"refund":0,"opName":"CALL"},
{"pc":0,"op":96,"gas":"0x8cc","gasCost":"0x3","memSize":0,"stack":[],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":2,"op":128,"gas":"0x8c9","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":4,"refund":0,"opName":"DUP1"},
{"pc":3,"op":83,"gas":"0x8c6","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":4,"refund":0,"opName":"MSTORE8"},
{"pc":4,"op":96,"gas":"0x8ba","gasCost":"0x3","memSize":96,"stack":[],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":6,"op":96,"gas":"0x8b7","gasCost":"0x3","memSize":96,"stack":["0x40"],"depth":4,"refund":0,"opName":"PUSH1"},
{"pc":8,"op":85,"gas":"0x8b4","gasCost":"0x8fc","memSize":96,"stack":["0x40","0x40"],"depth":4,"refund":0,"opName":"SSTORE","error":"Out of gas"},
{"pc":22,"op":96,"gas":"0x23","gasCost":"0x3","memSize":96,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x20","gasCost":"0x0","memSize":96,"stack":["0x0","0x40"],"depth":3,"refund":0,"opName":"RETURN"},
{"pc":22,"op":96,"gas":"0x48","gasCost":"0x3","memSize":96,"stack":["0x1"],"depth":2,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x45","gasCost":"0x0","memSize":96,"stack":["0x1","0x40"],"depth":2,"refund":0,"opName":"RETURN"},
{"pc":22,"op":96,"gas":"0x71","gasCost":"0x3","memSize":96,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"},
{"pc":24,"op":243,"gas":"0x6e","gasCost":"0x0","memSize":96,"stack":["0x1","0x40"],"depth":1,"refund":0,"opName":"RETURN"},
{"gasUser":"0x619e","gasTotal":"0x619e","output":"0x40"}
]
}

@ -146,7 +146,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return the gas available to execute the child message call
*/
protected abstract long gasAvailableForChildCall(MessageFrame frame);
public abstract long gasAvailableForChildCall(MessageFrame frame);
/**
* Returns whether the child message call should be static.

@ -20,6 +20,7 @@ import static com.google.common.base.Strings.padStart;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.AbstractCallOperation;
import org.hyperledger.besu.evm.operation.Operation;
import java.io.PrintStream;
@ -174,6 +175,10 @@ public class StandardJsonTracer implements OperationTracer {
}
final int opcode = currentOp.getOpcode();
final Bytes returnData = messageFrame.getReturnData();
long thisGasCost = executeResult.getGasCost();
if (currentOp instanceof AbstractCallOperation) {
thisGasCost += messageFrame.getMessageFrameStack().getFirst().getRemainingGas();
}
final StringBuilder sb = new StringBuilder(1024);
sb.append("{");
@ -183,7 +188,7 @@ public class StandardJsonTracer implements OperationTracer {
}
sb.append("\"op\":").append(opcode).append(",");
sb.append("\"gas\":\"").append(gas).append("\",");
sb.append("\"gasCost\":\"").append(shortNumber(executeResult.getGasCost())).append("\",");
sb.append("\"gasCost\":\"").append(shortNumber(thisGasCost)).append("\",");
if (memory != null) {
sb.append("\"memory\":\"").append(memory.toHexString()).append("\",");
}

@ -49,12 +49,10 @@ class StandardJsonTracerTest {
// returnStack was a valid field. It no longer appears in any traces.
// (b) the summary line is omitted
// (c) pc:3 is in error, the size of the memory before the first MSTORE8 is zero.
// (d) we don't report call requested gas in CALL series operations as a gas cost, just the EVM
// consumed gas
// (e) if memory is zero length, it is not included even if `showMemory` is true
// (f) if return data is zero length or null, it is not included even if `showReturnData` is
// (d) if memory is zero length, it is not included even if `showMemory` is true
// (e) if return data is zero length or null, it is not included even if `showReturnData` is
// true
// (g) if error is zero length or null it is not included.
// (f) if error is zero length or null it is not included.
assertThat(baos)
.hasToString(
"""
@ -70,7 +68,7 @@ class StandardJsonTracerTest {
{"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2"],"depth":1,"refund":0,"opName":"GAS"}
{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x2bc","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"depth":1,"refund":0,"opName":"STATICCALL"}
{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x24abb676c","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"depth":1,"refund":0,"opName":"STATICCALL"}
{"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"PUSH1"}
{"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1","0x40"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"RETURN"}
""");
@ -104,7 +102,7 @@ class StandardJsonTracerTest {
{"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}}
{"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}}
{"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memSize":96,"depth":1,"refund":0,"opName":"GAS","storage":{"0x40":"0x40"}}
{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x2bc","memSize":96,"depth":1,"refund":0,"opName":"STATICCALL","storage":{"0x40":"0x40"}}
{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x24abb676c","memSize":96,"depth":1,"refund":0,"opName":"STATICCALL","storage":{"0x40":"0x40"}}
{"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}}
{"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memSize":96,"depth":1,"refund":0,"opName":"RETURN","storage":{"0x40":"0x40"}}
""");

Loading…
Cancel
Save