Skip to content

Commit

Permalink
Add world context to transaction tracing API (hyperledger#5836)
Browse files Browse the repository at this point in the history
* Add world context to transaction tracing API

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>

* Update changelog with PR ID

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>

* Add the Transaction to traceEndTransaction

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>

* Rebase on main

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>

* Add receipt-linked information to the transaction tracer

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>

* added test

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

---------

Signed-off-by: Franklin Delehelle <franklin.delehelle@odena.eu>
Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Co-authored-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
  • Loading branch information
3 people authored and siladu committed Sep 20, 2023
1 parent 46c2bbe commit 0ec2f69
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 23.7.3
### Additions and Improvements
- Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836)

### Breaking Changes
- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,12 @@ private List<TransactionProcessingResult> trace(
.map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent))
.orElse(BlobGas.ZERO));

tracer.traceStartTransaction(transaction);

final WorldUpdater worldUpdater = chainUpdater.getNextUpdater();
tracer.traceStartTransaction(worldUpdater, transaction);
final TransactionProcessingResult result =
transactionProcessor.processTransaction(
blockchain,
chainUpdater.getNextUpdater(),
worldUpdater,
header,
transaction,
header.getCoinbase(),
Expand All @@ -188,7 +188,14 @@ private List<TransactionProcessingResult> trace(
blobGasPrice);

long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining();
tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0);
tracer.traceEndTransaction(
worldUpdater,
transaction,
result.isSuccessful(),
result.getOutput(),
result.getLogs(),
transactionGasUsed,
0);

results.add(result);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@
import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.worldstate.WorldView;
import org.hyperledger.besu.plugin.services.TraceService;
import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;

import java.util.List;

import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -102,4 +109,103 @@ void shouldRetrieveStateUpdatePostTracingForAllBlocks() {
assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce())
.isEqualTo(persistedNonceForAccount);
}

@Test
void shouldReturnTheCorrectWorldViewForTxStartEnd() {
final TxStartEndTracer txStartEndTracer = new TxStartEndTracer();

// block contains 1 transaction
traceService.traceBlock(31, txStartEndTracer);

assertThat(txStartEndTracer.txStartWorldView).isNotNull();
assertThat(txStartEndTracer.txEndWorldView).isNotNull();

assertThat(txStartEndTracer.txStartTransaction.getNonce())
.isEqualTo(txStartEndTracer.txEndTransaction.getNonce())
.isEqualTo(30);
assertThat(txStartEndTracer.txStartTransaction.getGasLimit())
.isEqualTo(txStartEndTracer.txEndTransaction.getGasLimit())
.isEqualTo(314159);
assertThat(txStartEndTracer.txStartTransaction.getTo().get())
.isEqualTo(txStartEndTracer.txEndTransaction.getTo().get())
.isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"));
assertThat(txStartEndTracer.txStartTransaction.getValue())
.isEqualTo(txStartEndTracer.txEndTransaction.getValue())
.isEqualTo(
Wei.fromHexString(
"0x000000000000000000000000000000000000000000000000000000000000000a"));
assertThat(txStartEndTracer.txStartTransaction.getPayload())
.isEqualTo(txStartEndTracer.txEndTransaction.getPayload())
.isEqualTo(Bytes.fromHexString("0xfd408767"));

assertThat(txStartEndTracer.txEndStatus).isTrue();
assertThat(txStartEndTracer.txEndOutput).isEqualTo(Bytes.fromHexString("0x"));
assertThat(txStartEndTracer.txEndGasUsed).isEqualTo(24303);
assertThat(txStartEndTracer.txEndTimeNs).isNotNull();

assertThat(txStartEndTracer.txEndLogs).isNotEmpty();

final Log actualLog = txStartEndTracer.txEndLogs.get(0);
assertThat(actualLog.getLogger())
.isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"));
assertThat(actualLog.getData())
.isEqualTo(
Bytes.fromHexString(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a"));
assertThat(actualLog.getTopics()).hasSize(4);
assertThat(actualLog.getTopics().get(0))
.isEqualTo(
Bytes.fromHexString(
"0xd5f0a30e4be0c6be577a71eceb7464245a796a7e6a55c0d971837b250de05f4e"));
assertThat(actualLog.getTopics().get(1))
.isEqualTo(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000001"));
assertThat(actualLog.getTopics().get(2))
.isEqualTo(
Bytes.fromHexString(
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"));
assertThat(actualLog.getTopics().get(3))
.isEqualTo(
Bytes.fromHexString(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
}

private static class TxStartEndTracer implements BlockAwareOperationTracer {
public WorldView txStartWorldView;
public WorldView txEndWorldView;

public Transaction txStartTransaction;
public Transaction txEndTransaction;

public boolean txEndStatus;
public Bytes txEndOutput;
public List<Log> txEndLogs;
public long txEndGasUsed;
public Long txEndTimeNs;

@Override
public void traceStartTransaction(final WorldView worldView, final Transaction transaction) {
txStartWorldView = worldView;
txStartTransaction = transaction;
}

@Override
public void traceEndTransaction(
final WorldView worldView,
final Transaction transaction,
final boolean status,
final Bytes output,
final List<Log> logs,
final long gasUsed,
final long timeNs) {
txEndWorldView = worldView;
txEndTransaction = transaction;
txEndStatus = status;
txEndOutput = output;
txEndLogs = logs;
txEndGasUsed = gasUsed;
txEndTimeNs = timeNs;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ static T8nResult runTest(
final TransactionProcessingResult result;
try {
tracer = tracerManager.getManagedTracer(i, transaction.getHash());
tracer.traceStartTransaction(worldStateUpdater, transaction);
result =
processor.processTransaction(
blockchain,
Expand Down Expand Up @@ -312,12 +313,18 @@ static T8nResult runTest(
.getGasCalculator()
.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.getTo().isEmpty());
tracer.traceEndTransaction(
result.getOutput(), gasUsed - intrinsicGas, timer.elapsed(TimeUnit.NANOSECONDS));
TransactionReceipt receipt =
protocolSpec
.getTransactionReceiptFactory()
.create(transaction.getType(), result, worldState, gasUsed);
tracer.traceEndTransaction(
worldStateUpdater,
transaction,
result.isSuccessful(),
result.getOutput(),
result.getLogs(),
gasUsed - intrinsicGas,
timer.elapsed(TimeUnit.NANOSECONDS));
Bytes gasUsedInTransaction = Bytes.ofUnsignedLong(transactionGasUsed);
receipts.add(receipt);
ObjectNode receiptObject = receiptsArray.addObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.worldstate.WorldView;

import java.util.List;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;
Expand Down Expand Up @@ -67,18 +70,30 @@ default void traceAccountCreationResult(
/**
* Trace the start of a transaction.
*
* @param worldView an immutable view of the execution context
* @param transaction the transaction which will be processed
*/
default void traceStartTransaction(final Transaction transaction) {}
default void traceStartTransaction(final WorldView worldView, final Transaction transaction) {}

/**
* Trace the end of a transaction.
*
* @param worldView an immutable view of the execution context
* @param tx the transaction that just concluded
* @param status true if the transaction is successful, false otherwise
* @param output the bytes output from the transaction
* @param logs the logs emitted by this transaction
* @param gasUsed the gas used by the entire transaction
* @param timeNs the time in nanoseconds it took to execute the transaction
*/
default void traceEndTransaction(final Bytes output, final long gasUsed, final long timeNs) {}
default void traceEndTransaction(
final WorldView worldView,
final Transaction tx,
final boolean status,
final Bytes output,
final List<Log> logs,
final long gasUsed,
final long timeNs) {}

/**
* Trace the entering of a new context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@

import static com.google.common.base.Strings.padStart;

import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.worldstate.WorldView;

import java.io.PrintStream;
import java.io.PrintWriter;
Expand Down Expand Up @@ -216,7 +219,14 @@ public void traceAccountCreationResult(
}

@Override
public void traceEndTransaction(final Bytes output, final long gasUsed, final long timeNs) {
public void traceEndTransaction(
final WorldView _worldView,
final Transaction _tx,
final boolean _status,
final Bytes output,
final List<Log> _logs,
final long gasUsed,
final long timeNs) {
final StringBuilder sb = new StringBuilder(1024);
sb.append("{");
if (output.size() > 0) {
Expand Down

0 comments on commit 0ec2f69

Please sign in to comment.