Search in sources :

Example 1 with TraceFrame

use of org.hyperledger.besu.ethereum.debug.TraceFrame in project besu by hyperledger.

the class DebugOperationTracer method tracePrecompileCall.

@Override
public void tracePrecompileCall(final MessageFrame frame, final Gas gasRequirement, final Bytes output) {
    if (traceFrames.isEmpty()) {
        final TraceFrame traceFrame = new TraceFrame(frame.getPC(), Optional.empty(), frame.getRemainingGas(), Optional.empty(), frame.getGasRefund(), frame.getMessageStackDepth(), Optional.empty(), frame.getRecipientAddress(), frame.getValue(), frame.getInputData().copy(), frame.getOutputData(), Optional.empty(), Optional.empty(), Optional.empty(), frame.getWorldUpdater(), Optional.empty(), Optional.ofNullable(frame.getRefunds()), Optional.ofNullable(frame.getCode()), frame.getMaxStackSize(), Optional.empty(), true, Optional.empty(), Optional.empty());
        traceFrames.add(traceFrame);
    }
    traceFrames.get(traceFrames.size() - 1).setPrecompiledGasCost(Optional.of(gasRequirement));
}
Also used : TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame)

Example 2 with TraceFrame

use of org.hyperledger.besu.ethereum.debug.TraceFrame in project besu by hyperledger.

the class DebugTraceBlockByHashTest method shouldReturnCorrectResponse.

@Test
public void shouldReturnCorrectResponse() {
    final Object[] params = new Object[] { blockHash };
    final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlockByHash", params));
    final TraceFrame traceFrame = new TraceFrame(12, Optional.of("NONE"), 45L, OptionalLong.of(56L), 0L, 2, Optional.empty(), null, Wei.ZERO, Bytes.EMPTY, Bytes.EMPTY, Optional.empty(), Optional.empty(), Optional.empty(), null, Optional.empty(), Optional.empty(), Optional.empty(), 0, Optional.empty(), false, Optional.empty(), Optional.empty());
    final TransactionProcessingResult transaction1Result = mock(TransactionProcessingResult.class);
    final TransactionProcessingResult transaction2Result = mock(TransactionProcessingResult.class);
    final TransactionTrace transaction1Trace = mock(TransactionTrace.class);
    final TransactionTrace transaction2Trace = mock(TransactionTrace.class);
    BlockTrace blockTrace = new BlockTrace(Arrays.asList(transaction1Trace, transaction2Trace));
    when(transaction1Trace.getTraceFrames()).thenReturn(Arrays.asList(traceFrame));
    when(transaction2Trace.getTraceFrames()).thenReturn(Arrays.asList(traceFrame));
    when(transaction1Trace.getResult()).thenReturn(transaction1Result);
    when(transaction2Trace.getResult()).thenReturn(transaction2Result);
    when(transaction1Result.getOutput()).thenReturn(Bytes.fromHexString("1234"));
    when(transaction2Result.getOutput()).thenReturn(Bytes.fromHexString("1234"));
    when(blockTracer.trace(eq(blockHash), any())).thenReturn(Optional.of(blockTrace));
    final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) debugTraceBlockByHash.response(request);
    final Collection<?> result = (Collection<?>) response.getResult();
    assertThat(result).hasSize(2);
}
Also used : JsonRpcRequestContext(org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext) JsonRpcRequest(org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest) TransactionTrace(org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace) Collection(java.util.Collection) BlockTrace(org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace) JsonRpcSuccessResponse(org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) Test(org.junit.Test)

Example 3 with TraceFrame

use of org.hyperledger.besu.ethereum.debug.TraceFrame in project besu by hyperledger.

the class DebugTraceBlockByNumberTest method shouldReturnCorrectResponse.

@Test
public void shouldReturnCorrectResponse() {
    final long blockNumber = 1L;
    final Object[] params = new Object[] { Long.toHexString(blockNumber) };
    final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlockByNumber", params));
    final TraceFrame traceFrame = new TraceFrame(12, Optional.of("NONE"), 45L, OptionalLong.of(56L), 0L, 2, Optional.empty(), null, Wei.ZERO, Bytes.EMPTY, Bytes.EMPTY, Optional.empty(), Optional.empty(), Optional.empty(), null, Optional.empty(), Optional.empty(), Optional.empty(), 0, Optional.empty(), false, Optional.empty(), Optional.empty());
    final TransactionProcessingResult transaction1Result = mock(TransactionProcessingResult.class);
    final TransactionProcessingResult transaction2Result = mock(TransactionProcessingResult.class);
    final TransactionTrace transaction1Trace = mock(TransactionTrace.class);
    final TransactionTrace transaction2Trace = mock(TransactionTrace.class);
    final BlockTrace blockTrace = new BlockTrace(asList(transaction1Trace, transaction2Trace));
    when(transaction1Trace.getTraceFrames()).thenReturn(singletonList(traceFrame));
    when(transaction2Trace.getTraceFrames()).thenReturn(singletonList(traceFrame));
    when(transaction1Trace.getResult()).thenReturn(transaction1Result);
    when(transaction2Trace.getResult()).thenReturn(transaction2Result);
    when(transaction1Result.getOutput()).thenReturn(Bytes.fromHexString("1234"));
    when(transaction2Result.getOutput()).thenReturn(Bytes.fromHexString("1234"));
    when(blockchain.getBlockHashByNumber(blockNumber)).thenReturn(Optional.of(blockHash));
    when(blockTracer.trace(eq(blockHash), any())).thenReturn(Optional.of(blockTrace));
    final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) debugTraceBlockByNumber.response(request);
    final Collection<DebugTraceTransactionResult> result = getResult(response);
    assertThat(result).usingFieldByFieldElementComparator().isEqualTo(DebugTraceTransactionResult.of(blockTrace.getTransactionTraces()));
}
Also used : DebugTraceTransactionResult(org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTransactionResult) JsonRpcRequestContext(org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext) JsonRpcRequest(org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest) TransactionTrace(org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace) BlockTrace(org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace) JsonRpcSuccessResponse(org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) Test(org.junit.Test)

Example 4 with TraceFrame

use of org.hyperledger.besu.ethereum.debug.TraceFrame in project besu by hyperledger.

the class StateDiffGenerator method generateStateDiff.

public Stream<Trace> generateStateDiff(final TransactionTrace transactionTrace) {
    final List<TraceFrame> traceFrames = transactionTrace.getTraceFrames();
    if (traceFrames.size() < 1) {
        return Stream.empty();
    }
    // This corresponds to the world state after the TX executed
    // It is two deep because of the way we addressed Spurious Dragon.
    final WorldUpdater transactionUpdater = traceFrames.get(0).getWorldUpdater().parentUpdater().get().parentUpdater().get();
    // This corresponds to the world state prior to the TX execution,
    // Either the initial block state or the state of the prior TX
    final WorldUpdater previousUpdater = transactionUpdater.parentUpdater().get();
    final StateDiffTrace stateDiffResult = new StateDiffTrace();
    for (final Account updatedAccount : transactionUpdater.getTouchedAccounts()) {
        final Address accountAddress = updatedAccount.getAddress();
        final Account rootAccount = previousUpdater.get(accountAddress);
        // calculate storage diff
        final Map<String, DiffNode> storageDiff = new TreeMap<>();
        for (final Map.Entry<UInt256, UInt256> entry : ((UpdateTrackingAccount<?>) updatedAccount).getUpdatedStorage().entrySet()) {
            // FIXME cast
            final UInt256 newValue = entry.getValue();
            if (rootAccount == null) {
                if (!UInt256.ZERO.equals(newValue)) {
                    storageDiff.put(entry.getKey().toHexString(), new DiffNode(null, newValue.toHexString()));
                }
            } else {
                final UInt256 originalValue = rootAccount.getStorageValue(entry.getKey());
                if (!originalValue.equals(newValue)) {
                    storageDiff.put(entry.getKey().toHexString(), new DiffNode(originalValue.toHexString(), newValue.toHexString()));
                }
            }
        }
        // populate the diff object
        final AccountDiff accountDiff = new AccountDiff(createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::balanceAsHex), createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::codeAsHex), createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::nonceAsHex), storageDiff);
        if (accountDiff.hasDifference()) {
            stateDiffResult.put(accountAddress.toHexString(), accountDiff);
        }
    }
    // Add deleted accounts
    for (final Address accountAddress : transactionUpdater.getDeletedAccountAddresses()) {
        final Account deletedAccount = previousUpdater.get(accountAddress);
        if (deletedAccount == null) {
            continue;
        }
        final AccountDiff accountDiff = new AccountDiff(createDiffNode(deletedAccount, null, StateDiffGenerator::balanceAsHex), createDiffNode(deletedAccount, null, StateDiffGenerator::codeAsHex), createDiffNode(deletedAccount, null, StateDiffGenerator::nonceAsHex), Collections.emptyMap());
        stateDiffResult.put(accountAddress.toHexString(), accountDiff);
    }
    return Stream.of(stateDiffResult);
}
Also used : Account(org.hyperledger.besu.evm.account.Account) UpdateTrackingAccount(org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount) Address(org.hyperledger.besu.datatypes.Address) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) TreeMap(java.util.TreeMap) TreeMap(java.util.TreeMap) Map(java.util.Map) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame) UInt256(org.apache.tuweni.units.bigints.UInt256)

Example 5 with TraceFrame

use of org.hyperledger.besu.ethereum.debug.TraceFrame in project besu by hyperledger.

the class FlatTraceGenerator method generateFromTransactionTrace.

/**
 * Generates a stream of {@link Trace} from the passed {@link TransactionTrace} data.
 *
 * @param protocolSchedule the current {@link ProtocolSchedule} to use
 * @param transactionTrace the {@link TransactionTrace} to use
 * @param block the {@link Block} to use
 * @param traceCounter the current trace counter value
 * @param consumer to use to add additional contextual information to the trace
 * @return a stream of generated traces {@link Trace}
 */
public static Stream<Trace> generateFromTransactionTrace(final ProtocolSchedule protocolSchedule, final TransactionTrace transactionTrace, final Block block, final AtomicInteger traceCounter, final Consumer<FlatTrace.Builder> consumer) {
    final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.freshBuilder(transactionTrace);
    final Transaction tx = transactionTrace.getTransaction();
    final Optional<String> smartContractCode = tx.getInit().map(__ -> transactionTrace.getResult().getOutput().toString());
    final Optional<String> smartContractAddress = smartContractCode.map(__ -> Address.contractAddress(tx.getSender(), tx.getNonce()).toHexString());
    final Optional<Bytes> revertReason = transactionTrace.getResult().getRevertReason();
    // set code field in result node
    smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder()::code);
    revertReason.ifPresent(r -> firstFlatTraceBuilder.revertReason(r.toHexString()));
    // set init field if transaction is a smart contract deployment
    tx.getInit().map(Bytes::toHexString).ifPresent(firstFlatTraceBuilder.getActionBuilder()::init);
    // set to, input and callType fields if not a smart contract
    if (tx.getTo().isPresent()) {
        final Bytes payload = tx.getPayload();
        firstFlatTraceBuilder.getActionBuilder().to(tx.getTo().map(Bytes::toHexString).orElse(null)).callType("call").input(payload == null ? "0x" : payload.toHexString());
        if (!transactionTrace.getTraceFrames().isEmpty() && hasRevertInSubCall(transactionTrace, transactionTrace.getTraceFrames().get(0))) {
            firstFlatTraceBuilder.error(Optional.of("Reverted"));
        }
    } else {
        firstFlatTraceBuilder.type("create").getResultBuilder().address(smartContractAddress.orElse(null));
    }
    if (!transactionTrace.getTraceFrames().isEmpty()) {
        final OptionalLong precompiledGasCost = transactionTrace.getTraceFrames().get(0).getPrecompiledGasCost();
        if (precompiledGasCost.isPresent()) {
            firstFlatTraceBuilder.getResultBuilder().gasUsed("0x" + Long.toHexString(precompiledGasCost.getAsLong()));
        }
    }
    final List<FlatTrace.Builder> flatTraces = new ArrayList<>();
    // stack of previous contexts
    final Deque<FlatTrace.Context> tracesContexts = new ArrayDeque<>();
    // add the first transactionTrace context to the queue of transactionTrace contexts
    FlatTrace.Context currentContext = new FlatTrace.Context(firstFlatTraceBuilder);
    tracesContexts.addLast(currentContext);
    flatTraces.add(currentContext.getBuilder());
    // declare the first transactionTrace context as the previous transactionTrace context
    long cumulativeGasCost = 0;
    final Iterator<TraceFrame> iter = transactionTrace.getTraceFrames().iterator();
    Optional<TraceFrame> nextTraceFrame = iter.hasNext() ? Optional.of(iter.next()) : Optional.empty();
    while (nextTraceFrame.isPresent()) {
        final TraceFrame traceFrame = nextTraceFrame.get();
        nextTraceFrame = iter.hasNext() ? Optional.of(iter.next()) : Optional.empty();
        cumulativeGasCost += traceFrame.getGasCost().orElse(0L) + traceFrame.getPrecompiledGasCost().orElse(0L);
        final String opcodeString = traceFrame.getOpcode();
        if ("CALL".equals(opcodeString) || "CALLCODE".equals(opcodeString) || "DELEGATECALL".equals(opcodeString) || "STATICCALL".equals(opcodeString)) {
            currentContext = handleCall(transactionTrace, traceFrame, nextTraceFrame, flatTraces, cumulativeGasCost, tracesContexts, opcodeString.toLowerCase(Locale.US));
        } else if ("CALLDATALOAD".equals(opcodeString)) {
            currentContext = handleCallDataLoad(currentContext, traceFrame);
        } else if ("RETURN".equals(opcodeString) || "STOP".equals(opcodeString)) {
            currentContext = handleReturn(protocolSchedule, transactionTrace, block, traceFrame, tracesContexts, currentContext);
        } else if ("SELFDESTRUCT".equals(opcodeString)) {
            if (traceFrame.getExceptionalHaltReason().isPresent()) {
                currentContext = handleCall(transactionTrace, traceFrame, nextTraceFrame, flatTraces, cumulativeGasCost, tracesContexts, opcodeString.toLowerCase(Locale.US));
            } else {
                currentContext = handleSelfDestruct(traceFrame, tracesContexts, currentContext, flatTraces);
            }
        } else if (("CREATE".equals(opcodeString) || "CREATE2".equals(opcodeString)) && (traceFrame.getExceptionalHaltReason().isEmpty() || traceFrame.getDepth() == 0)) {
            currentContext = handleCreateOperation(traceFrame, nextTraceFrame, flatTraces, cumulativeGasCost, tracesContexts, smartContractAddress);
        } else if ("REVERT".equals(opcodeString)) {
            currentContext = handleRevert(tracesContexts, currentContext);
        }
        if (traceFrame.getExceptionalHaltReason().isPresent()) {
            currentContext = handleHalt(flatTraces, tracesContexts, currentContext, traceFrame);
        }
        if (currentContext == null) {
            break;
        }
    }
    return flatTraces.stream().peek(consumer).map(FlatTrace.Builder::build);
}
Also used : ArrayList(java.util.ArrayList) ArrayDeque(java.util.ArrayDeque) Bytes(org.apache.tuweni.bytes.Bytes) Transaction(org.hyperledger.besu.ethereum.core.Transaction) OptionalLong(java.util.OptionalLong) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame)

Aggregations

TraceFrame (org.hyperledger.besu.ethereum.debug.TraceFrame)26 Test (org.junit.Test)16 TraceOptions (org.hyperledger.besu.ethereum.debug.TraceOptions)9 MessageFrame (org.hyperledger.besu.evm.frame.MessageFrame)9 TransactionTrace (org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace)6 TransactionProcessingResult (org.hyperledger.besu.ethereum.processing.TransactionProcessingResult)6 JsonRpcRequest (org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest)5 JsonRpcRequestContext (org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext)5 JsonRpcSuccessResponse (org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse)5 Bytes (org.apache.tuweni.bytes.Bytes)4 UInt256 (org.apache.tuweni.units.bigints.UInt256)4 Transaction (org.hyperledger.besu.ethereum.core.Transaction)4 BlockTrace (org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTrace)3 WorldUpdater (org.hyperledger.besu.evm.worldstate.WorldUpdater)3 ArrayDeque (java.util.ArrayDeque)2 ArrayList (java.util.ArrayList)2 Collection (java.util.Collection)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 OptionalLong (java.util.OptionalLong)2