From f42f8c1122bda2618277e72dc5799d2700ac0caf Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:21:38 +1000 Subject: [PATCH] Make tracer in block building block aware (#6135) Signed-off-by: stefan.pingel@consensys.net --- .../blockcreation/AbstractBlockCreator.java | 39 +++++++++++++------ .../txselection/BlockTransactionSelector.java | 18 ++++----- .../AbstractBlockTransactionSelectorTest.java | 4 +- .../mainnet/MainnetTransactionProcessor.java | 11 ++++++ .../besu/evm/tracing/StandardJsonTracer.java | 25 ------------ plugin-api/build.gradle | 2 +- .../tracer/BlockAwareOperationTracer.java | 8 ++++ .../PluginTransactionSelector.java | 6 +-- 8 files changed, 60 insertions(+), 53 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index 1954e3e400..668a875ff3 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; +import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AllAcceptingTransactionSelector; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -56,6 +57,9 @@ import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; +import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelectorFactory; import java.math.BigInteger; import java.util.List; @@ -183,13 +187,26 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator { disposableWorldState.updater(), timestamp, bytes32)); throwIfStopped(); + + final PluginTransactionSelector pluginTransactionSelector = + protocolContext + .getTransactionSelectorFactory() + .map(PluginTransactionSelectorFactory::create) + .orElseGet(() -> AllAcceptingTransactionSelector.INSTANCE); + + final BlockAwareOperationTracer operationTracer = + pluginTransactionSelector.getOperationTracer(); + + operationTracer.traceStartBlock(processableBlockHeader); + final TransactionSelectionResults transactionResults = selectTransactions( processableBlockHeader, disposableWorldState, maybeTransactions, miningBeneficiary, - newProtocolSpec); + newProtocolSpec, + pluginTransactionSelector); transactionResults.logSelectionStats(); @@ -261,14 +278,13 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator { final Optional> withdrawals = withdrawalsCanBeProcessed ? maybeWithdrawals : Optional.empty(); - final Block block = - new Block( - blockHeader, - new BlockBody( - transactionResults.getSelectedTransactions(), - ommers, - withdrawals, - maybeDeposits)); + final BlockBody blockBody = + new BlockBody( + transactionResults.getSelectedTransactions(), ommers, withdrawals, maybeDeposits); + final Block block = new Block(blockHeader, blockBody); + + operationTracer.traceEndBlock(blockHeader, blockBody); + return new BlockCreationResult(block, transactionResults); } catch (final SecurityModuleException ex) { throw new IllegalStateException("Failed to create block signature", ex); @@ -316,7 +332,8 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator { final MutableWorldState disposableWorldState, final Optional> transactions, final Address miningBeneficiary, - final ProtocolSpec protocolSpec) + final ProtocolSpec protocolSpec, + final PluginTransactionSelector pluginTransactionSelector) throws RuntimeException { final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); @@ -343,7 +360,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator { protocolSpec.getFeeMarket(), protocolSpec.getGasCalculator(), protocolSpec.getGasLimitCalculator(), - protocolContext.getTransactionSelectorFactory()); + pluginTransactionSelector); if (transactions.isPresent()) { return selector.evaluateTransactions(transactions.get()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java index 5e4f5caa55..7b1ad92ef8 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AbstractTransactionSelector; -import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AllAcceptingTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlobPriceTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlockSizeTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector; @@ -40,14 +39,12 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; -import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelectorFactory; import java.util.List; -import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.function.Supplier; @@ -87,7 +84,7 @@ public class BlockTransactionSelector { new TransactionSelectionResults(); private final List transactionSelectors; private final PluginTransactionSelector pluginTransactionSelector; - private final OperationTracer pluginOperationTracer; + private final BlockAwareOperationTracer pluginOperationTracer; public BlockTransactionSelector( final MiningParameters miningParameters, @@ -103,7 +100,7 @@ public class BlockTransactionSelector { final FeeMarket feeMarket, final GasCalculator gasCalculator, final GasLimitCalculator gasLimitCalculator, - final Optional transactionSelectorFactory) { + final PluginTransactionSelector pluginTransactionSelector) { this.transactionProcessor = transactionProcessor; this.blockchain = blockchain; this.worldState = worldState; @@ -120,11 +117,8 @@ public class BlockTransactionSelector { miningBeneficiary, transactionPool); transactionSelectors = createTransactionSelectors(blockSelectionContext); - pluginTransactionSelector = - transactionSelectorFactory - .map(PluginTransactionSelectorFactory::create) - .orElse(AllAcceptingTransactionSelector.INSTANCE); - pluginOperationTracer = pluginTransactionSelector.getOperationTracer(); + this.pluginTransactionSelector = pluginTransactionSelector; + this.pluginOperationTracer = pluginTransactionSelector.getOperationTracer(); } private List createTransactionSelectors( @@ -151,7 +145,9 @@ public class BlockTransactionSelector { .setMessage("Transaction pool stats {}") .addArgument(blockSelectionContext.transactionPool().logStats()) .log(); + blockSelectionContext.transactionPool().selectTransactions(this::evaluateTransaction); + LOG.atTrace() .setMessage("Transaction selection result {}") .addArgument(transactionSelectionResults::toTraceLog) diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index 39a4f0673e..ea138ab299 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -876,7 +876,7 @@ public abstract class AbstractBlockTransactionSelectorTest { getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), - Optional.empty()); + AllAcceptingTransactionSelector.INSTANCE); return selector; } @@ -902,7 +902,7 @@ public abstract class AbstractBlockTransactionSelectorTest { getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), - Optional.of(transactionSelectorFactory)); + transactionSelectorFactory.create()); return selector; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 35909c0c62..7e0a0da76b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -355,6 +355,8 @@ public class MainnetTransactionProcessor { contextVariablesBuilder.put(KEY_PRIVATE_METADATA_UPDATER, privateMetadataUpdater); } + operationTracer.traceStartTransaction(worldUpdater, transaction); + final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder() .maxStackSize(maxStackSize) @@ -451,6 +453,15 @@ public class MainnetTransactionProcessor { .log(); final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); + operationTracer.traceEndTransaction( + worldUpdater, + transaction, + initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS, + initialFrame.getOutputData(), + initialFrame.getLogs(), + gasUsedByTransaction, + 0L); + // update the coinbase final var coinbase = worldState.getOrCreate(miningBeneficiary); final long usedGas = transaction.getGasLimit() - refundedGas; diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java index e2c69f44d0..5d90107a69 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java @@ -18,13 +18,9 @@ package org.hyperledger.besu.evm.tracing; 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; @@ -256,25 +252,4 @@ public class StandardJsonTracer implements OperationTracer { final MessageFrame frame, final Optional haltReason) { // precompile calls are not part of the standard trace } - - @Override - public void traceEndTransaction( - final WorldView _worldView, - final Transaction _tx, - final boolean _status, - final Bytes output, - final List _logs, - final long gasUsed, - final long timeNs) { - final StringBuilder sb = new StringBuilder(1024); - sb.append("{"); - if (!output.isEmpty()) { - sb.append("\"output\":\"").append(output.toShortHexString()).append("\","); - } else { - sb.append("\"output\":\"\","); - } - sb.append("\"gasUsed\":\"").append(Words.longBytes(gasUsed).toShortHexString()).append("\","); - sb.append("\"time\":").append(timeNs).append("}"); - out.println(sb); - } } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index eaf03d74e7..94b2ad1461 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'YYrWGQIwp1sgEmwx2DcfjiskFO8euGGKeWh7Lq1F+24=' + knownHash = 'n4WfeMvltN4XWGtztd8ABjSU2TLiI3tk5yABivkgsFA=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java index 846f783b5f..f7dcc6113c 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.plugin.services.tracer; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; /** * An extended operation tracer that can trace the start and end of a block. @@ -47,6 +48,13 @@ public interface BlockAwareOperationTracer extends OperationTracer { */ default void traceEndBlock(final BlockHeader blockHeader, final BlockBody blockBody) {} + /** + * When building a block this API is called at the start of the process + * + * @param processableBlockHeader the processable header + */ + default void traceStartBlock(final ProcessableBlockHeader processableBlockHeader) {} + @Override default boolean isExtendedTracing() { return true; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/PluginTransactionSelector.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/PluginTransactionSelector.java index daa9327960..716a05e7d8 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/PluginTransactionSelector.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/PluginTransactionSelector.java @@ -16,10 +16,10 @@ package org.hyperledger.besu.plugin.services.txselection; import org.hyperledger.besu.datatypes.PendingTransaction; -import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; /** Interface for the transaction selector */ @Unstable @@ -31,8 +31,8 @@ public interface PluginTransactionSelector { * * @return OperationTracer to be used to trace candidate transactions */ - default OperationTracer getOperationTracer() { - return OperationTracer.NO_TRACING; + default BlockAwareOperationTracer getOperationTracer() { + return BlockAwareOperationTracer.NO_TRACING; } /**