Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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.datatypes;

/** Represent a transaction that has not confirmed yet, and stays in the transaction pool */
public interface PendingTransaction {
/**
* Get the underlying transaction
*
* @return the underlying transaction
*/
Transaction getTransaction();

/**
* Has this transaction been received from the RPC API?
*
* @return true if it is a local sent transaction
*/
boolean isReceivedFromLocalSource();

/**
* Timestamp in millisecond when this transaction has been added to the pool
*
* @return timestamp
*/
long getAddedAt();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
Expand Down Expand Up @@ -142,7 +143,8 @@ public TransactionSelectionResults buildTransactionListForBlock() {
pendingTransaction -> {
final var res = evaluateTransaction(pendingTransaction);
if (!res.selected()) {
transactionSelectionResults.updateNotSelected(pendingTransaction, res);
transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), res);
}
return res;
});
Expand All @@ -165,7 +167,7 @@ public TransactionSelectionResults buildTransactionListForBlock() {
public TransactionSelectionResults evaluateTransactions(final List<Transaction> transactions) {
transactions.forEach(
transaction -> {
final var res = evaluateTransaction(transaction);
final var res = evaluateTransaction(new PendingTransaction.Local(transaction));
if (!res.selected()) {
transactionSelectionResults.updateNotSelected(transaction, res);
}
Expand All @@ -182,12 +184,16 @@ public TransactionSelectionResults evaluateTransactions(final List<Transaction>
* the space remaining in the block.
*
*/
private TransactionSelectionResult evaluateTransaction(final Transaction transaction) {
private TransactionSelectionResult evaluateTransaction(
final PendingTransaction pendingTransaction) {
if (isCancelled.get()) {
throw new CancellationException("Cancelled during transaction selection.");
}

TransactionSelectionResult selectionResult = evaluateTransactionPreProcessing(transaction);
final Transaction transaction = pendingTransaction.getTransaction();

TransactionSelectionResult selectionResult =
evaluateTransactionPreProcessing(pendingTransaction);
if (!selectionResult.selected()) {
return selectionResult;
}
Expand All @@ -209,7 +215,7 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac
blockSelectionContext.blobGasPrice());

var transactionWithProcessingContextResult =
evaluateTransactionPostProcessing(transaction, effectiveResult);
evaluateTransactionPostProcessing(pendingTransaction, effectiveResult);
if (!transactionWithProcessingContextResult.selected()) {
return transactionWithProcessingContextResult;
}
Expand Down Expand Up @@ -243,16 +249,17 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac
* it then processes it through external selectors. If the transaction is selected by all
* selectors, it returns SELECTED.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction) {
final PendingTransaction pendingTransaction) {

// Process the transaction through internal selectors
for (var selector : transactionSelectors) {
TransactionSelectionResult result =
selector.evaluateTransactionPreProcessing(transaction, transactionSelectionResults);
selector.evaluateTransactionPreProcessing(
pendingTransaction, transactionSelectionResults);
// If the transaction is not selected by any internal selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result;
Expand All @@ -261,7 +268,8 @@ private TransactionSelectionResult evaluateTransactionPreProcessing(

// Process the transaction through external selectors
for (var selector : externalTransactionSelectors) {
TransactionSelectionResult result = selector.evaluateTransactionPreProcessing(transaction);
TransactionSelectionResult result =
selector.evaluateTransactionPreProcessing(pendingTransaction);
// If the transaction is not selected by any external selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result;
Expand All @@ -277,18 +285,19 @@ private TransactionSelectionResult evaluateTransactionPreProcessing(
* whether the transaction should be included in a block. If the transaction is selected by all
* selectors, it returns SELECTED.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @param processingResult The result of the transaction processing.
* @return The result of the transaction selection process.
*/
private TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final TransactionProcessingResult processingResult) {
final PendingTransaction pendingTransaction,
final TransactionProcessingResult processingResult) {

// Process the transaction through internal selectors
for (var selector : transactionSelectors) {
TransactionSelectionResult result =
selector.evaluateTransactionPostProcessing(
transaction, transactionSelectionResults, processingResult);
pendingTransaction, transactionSelectionResults, processingResult);
// If the transaction is not selected by any selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
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 @@ -34,24 +34,25 @@ public AbstractTransactionSelector(final BlockSelectionContext context) {
/**
* Evaluates a transaction in the context of other transactions in the same block.
*
* @param transaction The transaction to be evaluated within a block.
* @param pendingTransaction The transaction to be evaluated within a block.
* @param blockTransactionResults The results of other transaction evaluations in the same block.
* @return The result of the transaction evaluation
*/
public abstract TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults blockTransactionResults);
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults);

/**
* Evaluates a transaction considering other transactions in the same block and a transaction
* processing result.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @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 Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
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 @@ -38,22 +39,22 @@ public BlobPriceTransactionSelector(final BlockSelectionContext context) {
/**
* Evaluates a transaction considering its blob price.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @param ignored The results of other transaction evaluations in the same block.
* @return The result of the transaction selection.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults ignored) {
if (transactionBlobPriceBelowMin(transaction)) {
final PendingTransaction pendingTransaction, final TransactionSelectionResults ignored) {
if (transactionBlobPriceBelowMin(pendingTransaction.getTransaction())) {
return TransactionSelectionResult.BLOB_PRICE_BELOW_CURRENT_MIN;
}
return TransactionSelectionResult.SELECTED;
}

@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
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,19 +40,20 @@ public BlockSizeTransactionSelector(final BlockSelectionContext context) {
* Evaluates a transaction considering other transactions in the same block. If the transaction is
* too large for the block returns a selection result based on block occupancy.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @param transactionSelectionResults The results of other transaction evaluations in the same
* block.
* @return The result of the transaction selection.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults transactionSelectionResults) {
if (transactionTooLargeForBlock(transaction, transactionSelectionResults)) {
if (transactionTooLargeForBlock(
pendingTransaction.getTransaction(), transactionSelectionResults)) {
LOG.atTrace()
.setMessage("Transaction {} too large to select for block creation")
.addArgument(transaction::toTraceLog)
.addArgument(pendingTransaction::toTraceLog)
.log();
if (blockOccupancyAboveThreshold(transactionSelectionResults)) {
LOG.trace("Block occupancy above threshold, completing operation");
Expand All @@ -68,7 +70,7 @@ public TransactionSelectionResult evaluateTransactionPreProcessing(

@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
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 @@ -40,22 +41,22 @@ public PriceTransactionSelector(final BlockSelectionContext context) {
* Evaluates a transaction considering its price. If the transaction's current price is below the
* minimum, it returns a selection result indicating the reason.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @param ignored The results of other transaction evaluations in the same block.
* @return The result of the transaction selection.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults ignored) {
if (transactionCurrentPriceBelowMin(transaction)) {
final PendingTransaction pendingTransaction, final TransactionSelectionResults ignored) {
if (transactionCurrentPriceBelowMin(pendingTransaction)) {
return TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN;
}
return TransactionSelectionResult.SELECTED;
}

@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here.
Expand All @@ -65,14 +66,15 @@ public TransactionSelectionResult evaluateTransactionPostProcessing(
/**
* Checks if the transaction's current price is below the minimum.
*
* @param transaction The transaction to be checked.
* @param pendingTransaction The transaction to be checked.
* @return True if the transaction's current price is below the minimum, false otherwise.
*/
private boolean transactionCurrentPriceBelowMin(final Transaction transaction) {
private boolean transactionCurrentPriceBelowMin(final PendingTransaction pendingTransaction) {
final Transaction transaction = pendingTransaction.getTransaction();
// Here we only care about EIP1159 since for Frontier and local transactions the checks
// that we do when accepting them in the pool are enough
if (transaction.getType().supports1559FeeMarket()
&& !context.transactionPool().isLocalSender(transaction.getSender())) {
&& !pendingTransaction.isReceivedFromLocalSource()) {

// For EIP1559 transactions, the price is dynamic and depends on network conditions, so we can
// only calculate at this time the current minimum price the transaction is willing to pay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
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.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
Expand All @@ -40,7 +41,8 @@ public ProcessingResultTransactionSelector(final BlockSelectionContext context)

@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults blockTransactionResults) {
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults) {
// All checks depend on processingResult and will be done in the post-processing method, so
// nothing to do here.
return TransactionSelectionResult.SELECTED;
Expand All @@ -51,20 +53,20 @@ public TransactionSelectionResult evaluateTransactionPreProcessing(
* result. If the processing result is invalid, it determines the selection result for the invalid
* result.
*
* @param transaction The transaction to be evaluated.
* @param pendingTransaction The transaction to be evaluated.
* @param blockTransactionResults The results of other transaction evaluations in the same block.
* @param processingResult The processing result of the transaction.
* @return The result of the transaction selection.
*/
@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction,
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {

if (processingResult.isInvalid()) {
return transactionSelectionResultForInvalidResult(
transaction, processingResult.getValidationResult());
pendingTransaction.getTransaction(), processingResult.getValidationResult());
}
return TransactionSelectionResult.SELECTED;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,10 +552,10 @@ public void transactionSelectionPluginShouldWork() {

final TransactionSelectorFactory transactionSelectorFactory =
() ->
(tx) -> {
if (tx.equals(notSelectedTransient))
pendingTx -> {
if (pendingTx.getTransaction().equals(notSelectedTransient))
return TransactionSelectionResult.invalidTransient("transient");
if (tx.equals(notSelectedInvalid))
if (pendingTx.getTransaction().equals(notSelectedInvalid))
return TransactionSelectionResult.invalid("invalid");
return TransactionSelectionResult.SELECTED;
};
Expand All @@ -572,7 +572,7 @@ public void transactionSelectionPluginShouldWork() {
transactionSelectorFactory);

transactionPool.addRemoteTransactions(
List.of(selected, notSelectedInvalid, notSelectedTransient));
List.of(selected, notSelectedTransient, notSelectedInvalid));

final TransactionSelectionResults transactionSelectionResults =
selector.buildTransactionListForBlock();
Expand Down
Loading