Skip to content

Commit

Permalink
Introduce TransactionEvaluationContext to pass data between selectors…
Browse files Browse the repository at this point in the history
… and plugin (hyperledger#6381)


Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
  • Loading branch information
fab-10 authored Jan 12, 2024
1 parent 33df79d commit 540f5a4
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 122 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
### Additions and Improvements
- Optimize RocksDB WAL files, allows for faster restart and a more linear disk space utilization [#6328](https://github.com/hyperledger/besu/pull/6328)
- Disable transaction handling when the node is not in sync, to avoid unnecessary transaction validation work [#6302](https://github.com/hyperledger/besu/pull/6302)
- Introduce TransactionEvaluationContext to pass data between transaction selectors and plugin, during block creation [#6381](https://github.com/hyperledger/besu/pull/6381)
- Upgrade dependencies [#6377](https://github.com/hyperledger/besu/pull/6377)
- Upgrade `com.fasterxml.jackson` dependencies [#6378](https://github.com/hyperledger/besu/pull/6378)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,26 +228,42 @@ private TransactionSelectionResult evaluateTransaction(
final PendingTransaction pendingTransaction) {
checkCancellation();

final Stopwatch evaluationTimer = Stopwatch.createStarted();
final TransactionEvaluationContext evaluationContext =
createTransactionEvaluationContext(pendingTransaction);

TransactionSelectionResult selectionResult = evaluatePreProcessing(pendingTransaction);
TransactionSelectionResult selectionResult = evaluatePreProcessing(evaluationContext);
if (!selectionResult.selected()) {
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationTimer);
return handleTransactionNotSelected(evaluationContext, selectionResult);
}

final WorldUpdater txWorldStateUpdater = blockWorldStateUpdater.updater();
final TransactionProcessingResult processingResult =
processTransaction(pendingTransaction, txWorldStateUpdater);

var postProcessingSelectionResult =
evaluatePostProcessing(pendingTransaction, processingResult);
var postProcessingSelectionResult = evaluatePostProcessing(evaluationContext, processingResult);

if (postProcessingSelectionResult.selected()) {
return handleTransactionSelected(
pendingTransaction, processingResult, txWorldStateUpdater, evaluationTimer);
return handleTransactionSelected(evaluationContext, processingResult, txWorldStateUpdater);
}
return handleTransactionNotSelected(
pendingTransaction, postProcessingSelectionResult, txWorldStateUpdater, evaluationTimer);
evaluationContext, postProcessingSelectionResult, txWorldStateUpdater);
}

private TransactionEvaluationContext createTransactionEvaluationContext(
final PendingTransaction pendingTransaction) {
final Wei transactionGasPriceInBlock =
blockSelectionContext
.feeMarket()
.getTransactionPriceCalculator()
.price(
pendingTransaction.getTransaction(),
blockSelectionContext.processableBlockHeader().getBaseFee());

return new TransactionEvaluationContext(
pendingTransaction,
Stopwatch.createStarted(),
transactionGasPriceInBlock,
blockSelectionContext.miningParameters().getMinTransactionGasPrice());
}

/**
Expand All @@ -256,21 +272,20 @@ private TransactionSelectionResult evaluateTransaction(
* it then processes it through external selectors. If the transaction is selected by all
* selectors, it returns SELECTED.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection session data.
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult evaluatePreProcessing(
final PendingTransaction pendingTransaction) {
final TransactionEvaluationContext evaluationContext) {

for (var selector : transactionSelectors) {
TransactionSelectionResult result =
selector.evaluateTransactionPreProcessing(
pendingTransaction, transactionSelectionResults);
selector.evaluateTransactionPreProcessing(evaluationContext, transactionSelectionResults);
if (!result.equals(SELECTED)) {
return result;
}
}
return pluginTransactionSelector.evaluateTransactionPreProcessing(pendingTransaction);
return pluginTransactionSelector.evaluateTransactionPreProcessing(evaluationContext);
}

/**
Expand All @@ -279,24 +294,24 @@ private TransactionSelectionResult evaluatePreProcessing(
* whether the transaction should be included in a block. If the transaction is selected by all
* selectors, it returns SELECTED.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection session data.
* @param processingResult The result of the transaction processing.
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult evaluatePostProcessing(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionProcessingResult processingResult) {

for (var selector : transactionSelectors) {
TransactionSelectionResult result =
selector.evaluateTransactionPostProcessing(
pendingTransaction, transactionSelectionResults, processingResult);
evaluationContext, transactionSelectionResults, processingResult);
if (!result.equals(SELECTED)) {
return result;
}
}
return pluginTransactionSelector.evaluateTransactionPostProcessing(
pendingTransaction, processingResult);
evaluationContext, processingResult);
}

/**
Expand Down Expand Up @@ -328,18 +343,16 @@ private TransactionProcessingResult processTransaction(
* receipt, updating the TransactionSelectionResults with the selected transaction, and notifying
* the external transaction selector.
*
* @param pendingTransaction The pending transaction.
* @param evaluationContext The current selection session data.
* @param processingResult The result of the transaction processing.
* @param txWorldStateUpdater The world state updater.
* @param evaluationTimer tracks the evaluation elapsed time
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult handleTransactionSelected(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionProcessingResult processingResult,
final WorldUpdater txWorldStateUpdater,
final Stopwatch evaluationTimer) {
final Transaction transaction = pendingTransaction.getTransaction();
final WorldUpdater txWorldStateUpdater) {
final Transaction transaction = evaluationContext.getTransaction();

final long gasUsedByTransaction =
transaction.getGasLimit() - processingResult.getGasRemaining();
Expand All @@ -363,13 +376,14 @@ private TransactionSelectionResult handleTransactionSelected(
transaction.getType(), processingResult, worldState, cumulativeGasUsed);

transactionSelectionResults.updateSelected(
pendingTransaction.getTransaction(), receipt, gasUsedByTransaction, blobGasUsed);
transaction, receipt, gasUsedByTransaction, blobGasUsed);
}
}

if (tooLate) {
// even if this tx passed all the checks, it is too late to include it in this block,
// so we need to treat it as not selected
final var evaluationTimer = evaluationContext.getEvaluationTimer();

// check if this tx took too much to evaluate, and in case remove it from the pool
final TransactionSelectionResult timeoutSelectionResult;
Expand All @@ -395,15 +409,15 @@ private TransactionSelectionResult handleTransactionSelected(
// do not rely on the presence of this result, since by the time it is added, the code
// reading it could have been already executed by another thread
return handleTransactionNotSelected(
pendingTransaction, timeoutSelectionResult, txWorldStateUpdater, evaluationTimer);
evaluationContext, timeoutSelectionResult, txWorldStateUpdater);
}

pluginTransactionSelector.onTransactionSelected(pendingTransaction, processingResult);
pluginTransactionSelector.onTransactionSelected(evaluationContext, processingResult);
blockWorldStateUpdater = worldState.updater();
LOG.atTrace()
.setMessage("Selected {} for block creation, evaluated in {}")
.addArgument(transaction::toTraceLog)
.addArgument(evaluationTimer)
.addArgument(evaluationContext.getPendingTransaction())
.log();
return SELECTED;
}
Expand All @@ -413,36 +427,35 @@ private TransactionSelectionResult handleTransactionSelected(
* TransactionSelectionResults with the unselected transaction, and notifies the external
* transaction selector.
*
* @param pendingTransaction The unselected pending transaction.
* @param evaluationContext The current selection session data.
* @param selectionResult The result of the transaction selection process.
* @param evaluationTimer tracks the evaluation elapsed time
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult handleTransactionNotSelected(
final PendingTransaction pendingTransaction,
final TransactionSelectionResult selectionResult,
final Stopwatch evaluationTimer) {
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResult selectionResult) {

final var pendingTransaction = evaluationContext.getPendingTransaction();

transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), selectionResult);
pluginTransactionSelector.onTransactionNotSelected(pendingTransaction, selectionResult);
evaluationContext.getTransaction(), selectionResult);
pluginTransactionSelector.onTransactionNotSelected(evaluationContext, selectionResult);
LOG.atTrace()
.setMessage("Not selected {} for block creation with result {}, evaluated in {}")
.addArgument(pendingTransaction::toTraceLog)
.addArgument(selectionResult)
.addArgument(evaluationTimer)
.addArgument(evaluationContext.getEvaluationTimer())
.log();

return selectionResult;
}

private TransactionSelectionResult handleTransactionNotSelected(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResult selectionResult,
final WorldUpdater txWorldStateUpdater,
final Stopwatch evaluationTimer) {
final WorldUpdater txWorldStateUpdater) {
txWorldStateUpdater.revert();
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationTimer);
return handleTransactionNotSelected(evaluationContext, selectionResult);
}

private void checkCancellation() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.blockcreation.txselection;

import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;

import com.google.common.base.Stopwatch;

public class TransactionEvaluationContext
implements org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext<
PendingTransaction> {
private final org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction
pendingTransaction;
private final Stopwatch evaluationTimer;
private final Wei transactionGasPrice;
private final Wei minGasPrice;

public TransactionEvaluationContext(
final PendingTransaction pendingTransaction,
final Stopwatch evaluationTimer,
final Wei transactionGasPrice,
final Wei minGasPrice) {
this.pendingTransaction = pendingTransaction;
this.evaluationTimer = evaluationTimer;
this.transactionGasPrice = transactionGasPrice;
this.minGasPrice = minGasPrice;
}

public Transaction getTransaction() {
return pendingTransaction.getTransaction();
}

@Override
public PendingTransaction getPendingTransaction() {
return pendingTransaction;
}

@Override
public Stopwatch getEvaluationTimer() {
return evaluationTimer;
}

@Override
public Wei getTransactionGasPrice() {
return transactionGasPrice;
}

@Override
public Wei getMinGasPrice() {
return minGasPrice;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors;

import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;

Expand All @@ -34,25 +34,25 @@ public AbstractTransactionSelector(final BlockSelectionContext context) {
/**
* Evaluates a transaction in the context of other transactions in the same block.
*
* @param pendingTransaction The transaction to be evaluated within a block.
* @param evaluationContext The current selection session data.
* @param blockTransactionResults The results of other transaction evaluations in the same block.
* @return The result of the transaction evaluation
*/
public abstract TransactionSelectionResult evaluateTransactionPreProcessing(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResults blockTransactionResults);

/**
* Evaluates a transaction considering other transactions in the same block and a transaction
* processing result.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection session data.
* @param blockTransactionResults The results of other transaction evaluations in the same block.
* @param processingResult The result of transaction processing.
* @return The result of the transaction evaluation
*/
public abstract TransactionSelectionResult evaluateTransactionPostProcessing(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hyperledger.besu.plugin.data.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector;
import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext;

/** A TransactionSelector that unconditionally selects all transactions. */
public class AllAcceptingTransactionSelector implements PluginTransactionSelector {
Expand All @@ -29,25 +30,25 @@ private AllAcceptingTransactionSelector() {}
/**
* Always selects the transaction in the pre-processing stage.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection context.
* @return Always SELECTED.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final PendingTransaction pendingTransaction) {
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext) {
return TransactionSelectionResult.SELECTED;
}

/**
* Always selects the transaction in the post-processing stage.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection context.
* @param processingResult The result of the transaction processing.
* @return Always SELECTED.
*/
@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
final TransactionProcessingResult processingResult) {
return TransactionSelectionResult.SELECTED;
}
Expand Down
Loading

0 comments on commit 540f5a4

Please sign in to comment.