From 987d33c63aa67194d8eb44c2532e7d6d483cc8ac Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 2 Oct 2023 10:41:21 +0200 Subject: [PATCH] Use PendingTransaction in BlockTransactionSelector (#5966) Signed-off-by: Fabio Di Fabio --- .../besu/datatypes/PendingTransaction.java | 39 ++++++++++ .../txselection/BlockTransactionSelector.java | 33 +++++--- .../AbstractTransactionSelector.java | 11 +-- .../BlobPriceTransactionSelector.java | 9 ++- .../BlockSizeTransactionSelector.java | 12 +-- .../selectors/PriceTransactionSelector.java | 16 ++-- .../ProcessingResultTransactionSelector.java | 10 ++- .../AbstractBlockTransactionSelectorTest.java | 8 +- .../core/AccountTransactionOrderTest.java | 73 ------------------ .../eth/transactions/PendingTransaction.java | 11 ++- .../eth/transactions/PendingTransactions.java | 2 +- .../layered/LayeredPendingTransactions.java | 3 +- .../AbstractPendingTransactionsSorter.java | 15 ++-- .../sorter}/AccountTransactionOrder.java | 24 +++--- .../LayeredPendingTransactionsTest.java | 34 ++++----- .../AbstractPendingTransactionsTestBase.java | 28 +++---- .../sorter/AccountTransactionOrderTest.java | 75 +++++++++++++++++++ plugin-api/build.gradle | 2 +- .../txselection/TransactionSelector.java | 7 +- 19 files changed, 237 insertions(+), 175 deletions(-) create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/PendingTransaction.java delete mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java rename ethereum/{core/src/main/java/org/hyperledger/besu/ethereum/core => eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter}/AccountTransactionOrder.java (70%) create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrderTest.java diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/PendingTransaction.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/PendingTransaction.java new file mode 100644 index 0000000000..4a8f5795ff --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/PendingTransaction.java @@ -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(); +} 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 68ea744406..679daa8b5e 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 @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState; 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; @@ -142,7 +143,8 @@ public class BlockTransactionSelector { pendingTransaction -> { final var res = evaluateTransaction(pendingTransaction); if (!res.selected()) { - transactionSelectionResults.updateNotSelected(pendingTransaction, res); + transactionSelectionResults.updateNotSelected( + pendingTransaction.getTransaction(), res); } return res; }); @@ -165,7 +167,7 @@ public class BlockTransactionSelector { public TransactionSelectionResults evaluateTransactions(final List transactions) { transactions.forEach( transaction -> { - final var res = evaluateTransaction(transaction); + final var res = evaluateTransaction(new PendingTransaction.Local(transaction)); if (!res.selected()) { transactionSelectionResults.updateNotSelected(transaction, res); } @@ -182,12 +184,16 @@ public class BlockTransactionSelector { * 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; } @@ -209,7 +215,7 @@ public class BlockTransactionSelector { blockSelectionContext.blobGasPrice()); var transactionWithProcessingContextResult = - evaluateTransactionPostProcessing(transaction, effectiveResult); + evaluateTransactionPostProcessing(pendingTransaction, effectiveResult); if (!transactionWithProcessingContextResult.selected()) { return transactionWithProcessingContextResult; } @@ -243,16 +249,17 @@ public class BlockTransactionSelector { * 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; @@ -261,7 +268,8 @@ public class BlockTransactionSelector { // 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; @@ -277,18 +285,19 @@ public class BlockTransactionSelector { * 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; diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/AbstractTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/AbstractTransactionSelector.java index 3e89bb6100..205e803e82 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/AbstractTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/AbstractTransactionSelector.java @@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors; 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; @@ -34,24 +34,25 @@ public abstract class AbstractTransactionSelector { /** * 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); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobPriceTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobPriceTransactionSelector.java index abf38621fd..56a17c2843 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobPriceTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobPriceTransactionSelector.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors; 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; @@ -38,14 +39,14 @@ public class BlobPriceTransactionSelector extends AbstractTransactionSelector { /** * 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; @@ -53,7 +54,7 @@ public class BlobPriceTransactionSelector extends AbstractTransactionSelector { @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. diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java index 7cef4995e5..5d60ef8fc6 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors; 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; @@ -39,19 +40,20 @@ public class BlockSizeTransactionSelector extends AbstractTransactionSelector { * 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"); @@ -68,7 +70,7 @@ public class BlockSizeTransactionSelector extends AbstractTransactionSelector { @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. diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java index 15755100e5..a6c1889e49 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Wei; 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; @@ -40,14 +41,14 @@ public class PriceTransactionSelector extends AbstractTransactionSelector { * 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; @@ -55,7 +56,7 @@ public class PriceTransactionSelector extends AbstractTransactionSelector { @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. @@ -65,14 +66,15 @@ public class PriceTransactionSelector extends AbstractTransactionSelector { /** * 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 diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java index 1fe71ee48f..8a2778eda0 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors; 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; @@ -40,7 +41,8 @@ public class ProcessingResultTransactionSelector extends AbstractTransactionSele @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; @@ -51,20 +53,20 @@ public class ProcessingResultTransactionSelector extends AbstractTransactionSele * 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; } 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 b15e61354b..d1af32dfe0 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 @@ -552,10 +552,10 @@ public abstract class AbstractBlockTransactionSelectorTest { 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; }; @@ -572,7 +572,7 @@ public abstract class AbstractBlockTransactionSelectorTest { transactionSelectorFactory); transactionPool.addRemoteTransactions( - List.of(selected, notSelectedInvalid, notSelectedTransient)); + List.of(selected, notSelectedTransient, notSelectedInvalid)); final TransactionSelectionResults transactionSelectionResults = selector.buildTransactionListForBlock(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java deleted file mode 100644 index 8f6c76ce03..0000000000 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.core; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; - -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; - -public class AccountTransactionOrderTest { - - private static final KeyPair KEYS = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - - private final Transaction transaction1 = transaction(1); - private final Transaction transaction2 = transaction(2); - private final Transaction transaction3 = transaction(3); - private final Transaction transaction4 = transaction(4); - private final AccountTransactionOrder accountTransactionOrder = - new AccountTransactionOrder( - Stream.of(transaction1, transaction2, transaction3, transaction4)); - - @Test - public void shouldProcessATransactionImmediatelyIfItsTheLowestNonce() { - assertThat(accountTransactionOrder.transactionsToProcess(transaction1)) - .containsExactly(transaction1); - } - - @Test - public void shouldDeferProcessingATransactionIfItIsNotTheLowestNonce() { - assertThat(accountTransactionOrder.transactionsToProcess(transaction2)).isEmpty(); - } - - @Test - public void shouldProcessDeferredTransactionsAfterPrerequisiteIsProcessed() { - assertThat(accountTransactionOrder.transactionsToProcess(transaction2)).isEmpty(); - assertThat(accountTransactionOrder.transactionsToProcess(transaction3)).isEmpty(); - - assertThat(accountTransactionOrder.transactionsToProcess(transaction1)) - .containsExactly(transaction1, transaction2, transaction3); - } - - @Test - public void shouldNotProcessDeferredTransactionsThatAreNotYetDue() { - assertThat(accountTransactionOrder.transactionsToProcess(transaction2)).isEmpty(); - assertThat(accountTransactionOrder.transactionsToProcess(transaction4)).isEmpty(); - - assertThat(accountTransactionOrder.transactionsToProcess(transaction1)) - .containsExactly(transaction1, transaction2); - - assertThat(accountTransactionOrder.transactionsToProcess(transaction3)) - .containsExactly(transaction3, transaction4); - } - - private Transaction transaction(final int nonce) { - return new TransactionTestFixture().nonce(nonce).createTransaction(KEYS); - } -} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java index 264537e125..a716b1675e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java @@ -28,7 +28,8 @@ import java.util.concurrent.atomic.AtomicLong; * Tracks the additional metadata associated with transactions to enable prioritization for mining * and deciding which transactions to drop when the transaction pool reaches its size limit. */ -public abstract class PendingTransaction { +public abstract class PendingTransaction + implements org.hyperledger.besu.datatypes.PendingTransaction { static final int NOT_INITIALIZED = -1; static final int FRONTIER_BASE_MEMORY_SIZE = 944; static final int ACCESS_LIST_BASE_MEMORY_SIZE = 944; @@ -52,6 +53,7 @@ public abstract class PendingTransaction { this.sequence = TRANSACTIONS_ADDED.getAndIncrement(); } + @Override public Transaction getTransaction() { return transaction; } @@ -72,12 +74,11 @@ public abstract class PendingTransaction { return transaction.getSender(); } - public abstract boolean isReceivedFromLocalSource(); - public Hash getHash() { return transaction.getHash(); } + @Override public long getAddedAt() { return addedAt; } @@ -184,6 +185,8 @@ public abstract class PendingTransaction { + addedAt + ", sequence=" + sequence + + ", isLocal=" + + isReceivedFromLocalSource() + '}'; } @@ -192,6 +195,8 @@ public abstract class PendingTransaction { + sequence + ", addedAt: " + addedAt + + ", isLocal=" + + isReceivedFromLocalSource() + ", " + transaction.toTraceLog() + "}"; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java index b8474d3d50..199e88675e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java @@ -88,6 +88,6 @@ public interface PendingTransactions { @FunctionalInterface interface TransactionSelector { - TransactionSelectionResult evaluateTransaction(Transaction transaction); + TransactionSelectionResult evaluateTransaction(PendingTransaction pendingTransaction); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactions.java index 0a802a7dd7..5502e9a6f1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactions.java @@ -342,8 +342,7 @@ public class LayeredPendingTransactions implements PendingTransactions { .forEach( candidatePendingTx -> { alreadyChecked.add(candidatePendingTx.getHash()); - final var res = - selector.evaluateTransaction(candidatePendingTx.getTransaction()); + final var res = selector.evaluateTransaction(candidatePendingTx); LOG.atTrace() .setMessage("Selection result {} for transaction {}") diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsSorter.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsSorter.java index 83424ae22f..ea12b3c4f6 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsSorter.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsSorter.java @@ -22,7 +22,6 @@ import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedRes import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.core.AccountTransactionOrder; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; @@ -259,16 +258,15 @@ public abstract class AbstractPendingTransactionsSorter implements PendingTransa accountTransactions.computeIfAbsent( highestPriorityPendingTransaction.getSender(), this::createSenderTransactionOrder); - for (final Transaction transactionToProcess : - accountTransactionOrder.transactionsToProcess( - highestPriorityPendingTransaction.getTransaction())) { + for (final PendingTransaction transactionToProcess : + accountTransactionOrder.transactionsToProcess(highestPriorityPendingTransaction)) { final TransactionSelectionResult result = selector.evaluateTransaction(transactionToProcess); if (result.discard()) { - transactionsToRemove.add(transactionToProcess); + transactionsToRemove.add(transactionToProcess.getTransaction()); transactionsToRemove.addAll( - signalInvalidAndGetDependentTransactions(transactionToProcess)); + signalInvalidAndGetDependentTransactions(transactionToProcess.getTransaction())); } if (result.stop()) { @@ -283,10 +281,7 @@ public abstract class AbstractPendingTransactionsSorter implements PendingTransa private AccountTransactionOrder createSenderTransactionOrder(final Address address) { return new AccountTransactionOrder( - transactionsBySender - .get(address) - .streamPendingTransactions() - .map(PendingTransaction::getTransaction)); + transactionsBySender.get(address).streamPendingTransactions()); } private TransactionAddedResult addTransactionForSenderAndNonce( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrder.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrder.java similarity index 70% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrder.java rename to ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrder.java index 721056103c..b85f88d556 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrder.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrder.java @@ -12,7 +12,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.core; +package org.hyperledger.besu.ethereum.eth.transactions.sorter; + +import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import java.util.ArrayList; import java.util.Comparator; @@ -23,12 +25,14 @@ import java.util.stream.Stream; public class AccountTransactionOrder { - private static final Comparator SORT_BY_NONCE = - Comparator.comparing(Transaction::getNonce); - private final NavigableSet transactionsForSender = new TreeSet<>(SORT_BY_NONCE); - private final NavigableSet deferredTransactions = new TreeSet<>(SORT_BY_NONCE); + private static final Comparator SORT_BY_NONCE = + Comparator.comparing(PendingTransaction::getNonce); + private final NavigableSet transactionsForSender = + new TreeSet<>(SORT_BY_NONCE); + private final NavigableSet deferredTransactions = + new TreeSet<>(SORT_BY_NONCE); - public AccountTransactionOrder(final Stream senderTransactions) { + public AccountTransactionOrder(final Stream senderTransactions) { senderTransactions.forEach(this.transactionsForSender::add); } @@ -44,14 +48,14 @@ public class AccountTransactionOrder { * order. Must be from the sender this instance is ordering. * @return the transactions from this sender that are now due to be processed, in order. */ - public Iterable transactionsToProcess( - final Transaction nextTransactionInPriorityOrder) { + public Iterable transactionsToProcess( + final PendingTransaction nextTransactionInPriorityOrder) { deferredTransactions.add(nextTransactionInPriorityOrder); - final List transactionsToApply = new ArrayList<>(); + final List transactionsToApply = new ArrayList<>(); while (!deferredTransactions.isEmpty() && !transactionsForSender.isEmpty() && deferredTransactions.first().equals(transactionsForSender.first())) { - final Transaction transaction = deferredTransactions.first(); + final PendingTransaction transaction = deferredTransactions.first(); transactionsToApply.add(transaction); deferredTransactions.remove(transaction); transactionsForSender.remove(transaction); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsTest.java index f3135045ad..7d044de859 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsTest.java @@ -302,8 +302,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List parsedTransactions = new ArrayList<>(); pendingTransactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTX -> { + parsedTransactions.add(pendingTX.getTransaction()); return selectionResult; }); @@ -322,8 +322,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List parsedTransactions = new ArrayList<>(); pendingTransactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return SELECTED; }); @@ -342,8 +342,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List parsedTransactions = new ArrayList<>(); pendingTransactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return SELECTED; }); @@ -363,8 +363,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List iterationOrder = new ArrayList<>(3); pendingTransactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); return SELECTED; }); @@ -387,10 +387,10 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List iterationOrder = new ArrayList<>(3); pendingTransactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); // pretending that the 2nd tx of the 1st sender is not selected - return transaction.getNonce() == 1 ? skipSelectionResult : SELECTED; + return pendingTx.getNonce() == 1 ? skipSelectionResult : SELECTED; }); // the 3rd tx of the 1st must not be processed, since the 2nd is skipped @@ -420,8 +420,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List iterationOrder = new ArrayList<>(2); pendingTransactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); return SELECTED; }); @@ -435,8 +435,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List parsedTransactions = new ArrayList<>(1); pendingTransactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name()); }); @@ -455,8 +455,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest { final List parsedTransactions = new ArrayList<>(1); pendingTransactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return TransactionSelectionResult.invalidTransient( GAS_PRICE_BELOW_CURRENT_BASE_FEE.name()); }); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java index 1aff575f2e..f1d9ce1016 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java @@ -315,8 +315,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List parsedTransactions = Lists.newArrayList(); transactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD; }); @@ -331,8 +331,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List parsedTransactions = Lists.newArrayList(); transactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return SELECTED; }); @@ -351,8 +351,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List parsedTransactions = Lists.newArrayList(); transactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return SELECTED; }); @@ -366,8 +366,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List parsedTransactions = Lists.newArrayList(); transactions.selectTransactions( - transaction -> { - parsedTransactions.add(transaction); + pendingTx -> { + parsedTransactions.add(pendingTx.getTransaction()); return TransactionSelectionResult.invalid( TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name()); }); @@ -535,8 +535,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List iterationOrder = new ArrayList<>(); transactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); return SELECTED; }); @@ -553,8 +553,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List iterationOrder = new ArrayList<>(); transactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); return SELECTED; }); @@ -575,8 +575,8 @@ public abstract class AbstractPendingTransactionsTestBase { final List iterationOrder = new ArrayList<>(); transactions.selectTransactions( - transaction -> { - iterationOrder.add(transaction); + pendingTx -> { + iterationOrder.add(pendingTx.getTransaction()); return SELECTED; }); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrderTest.java new file mode 100644 index 0000000000..b4bd59acb8 --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrderTest.java @@ -0,0 +1,75 @@ +/* + * Copyright ConsenSys AG. + * + * 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.eth.transactions.sorter; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class AccountTransactionOrderTest { + + private static final KeyPair KEYS = SignatureAlgorithmFactory.getInstance().generateKeyPair(); + + private final PendingTransaction pendingTx1 = new PendingTransaction.Remote((transaction(1))); + private final PendingTransaction pendingTx2 = new PendingTransaction.Remote((transaction(2))); + private final PendingTransaction pendingTx3 = new PendingTransaction.Remote((transaction(3))); + private final PendingTransaction pendingTx4 = new PendingTransaction.Remote((transaction(4))); + private final AccountTransactionOrder accountTransactionOrder = + new AccountTransactionOrder(Stream.of(pendingTx1, pendingTx2, pendingTx3, pendingTx4)); + + @Test + public void shouldProcessATransactionImmediatelyIfItsTheLowestNonce() { + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx1)) + .containsExactly(pendingTx1); + } + + @Test + public void shouldDeferProcessingATransactionIfItIsNotTheLowestNonce() { + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx2)).isEmpty(); + } + + @Test + public void shouldProcessDeferredTransactionsAfterPrerequisiteIsProcessed() { + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx2)).isEmpty(); + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx3)).isEmpty(); + + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx1)) + .containsExactly(pendingTx1, pendingTx2, pendingTx3); + } + + @Test + public void shouldNotProcessDeferredTransactionsThatAreNotYetDue() { + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx2)).isEmpty(); + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx4)).isEmpty(); + + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx1)) + .containsExactly(pendingTx1, pendingTx2); + + assertThat(accountTransactionOrder.transactionsToProcess(pendingTx3)) + .containsExactly(pendingTx3, pendingTx4); + } + + private Transaction transaction(final int nonce) { + return new TransactionTestFixture().nonce(nonce).createTransaction(KEYS); + } +} diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index b66f7fef94..79b4cbee85 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 = 'ON5/4jw14IPAL/Civ3ld6tvwrLsGS9eI38w5C0xRzdY=' + knownHash = 'gfZY0boUMYJoAHwou3eEhcz7A/xFvJKnjMUONZ6hY3I=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java index c2682b5d8a..601158a0fa 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.plugin.services.txselection; -import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; @@ -26,8 +26,9 @@ public interface TransactionSelector { * Method called to decide whether a transaction is added to a block. The result can also indicate * that no further transactions can be added to the block. * - * @param transaction candidate transaction + * @param pendingTransaction candidate transaction * @return TransactionSelectionResult that indicates whether to include the transaction */ - TransactionSelectionResult evaluateTransactionPreProcessing(Transaction transaction); + TransactionSelectionResult evaluateTransactionPreProcessing( + PendingTransaction pendingTransaction); }