Skip to content

Commit

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

* Introduce TransactionSelectionContext to pass data between selectors

Signed-off-by: Fabio Di Fabio <[email protected]>

* Use TransactionSelectionContext in all the methods of the plugin selector

Signed-off-by: Fabio Di Fabio <[email protected]>

---------

Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 authored Jan 10, 2024
1 parent 99b9ab3 commit c029a9f
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 122 deletions.
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
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.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;

Expand All @@ -39,22 +39,23 @@ public BlobPriceTransactionSelector(final BlockSelectionContext context) {
/**
* Evaluates a transaction considering its blob price.
*
* @param pendingTransaction The transaction to be evaluated.
* @param evaluationContext The current selection session data.
* @param ignored The results of other transaction evaluations in the same block.
* @return The result of the transaction selection.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final PendingTransaction pendingTransaction, final TransactionSelectionResults ignored) {
if (transactionBlobPriceBelowMin(pendingTransaction.getTransaction())) {
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResults ignored) {
if (transactionBlobPriceBelowMin(evaluationContext.getTransaction())) {
return TransactionSelectionResult.BLOB_PRICE_BELOW_CURRENT_MIN;
}
return TransactionSelectionResult.SELECTED;
}

@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final PendingTransaction pendingTransaction,
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here.
Expand Down
Loading

0 comments on commit c029a9f

Please sign in to comment.