Use PendingTransaction in BlockTransactionSelector (#5966)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
pull/5974/head
Fabio Di Fabio 1 year ago committed by GitHub
parent dc47867054
commit 987d33c63a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 39
      datatypes/src/main/java/org/hyperledger/besu/datatypes/PendingTransaction.java
  2. 33
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java
  3. 11
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/AbstractTransactionSelector.java
  4. 9
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobPriceTransactionSelector.java
  5. 12
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java
  6. 16
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java
  7. 10
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java
  8. 8
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  9. 73
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AccountTransactionOrderTest.java
  10. 11
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java
  11. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java
  12. 3
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactions.java
  13. 15
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsSorter.java
  14. 24
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrder.java
  15. 34
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsTest.java
  16. 28
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AbstractPendingTransactionsTestBase.java
  17. 75
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/sorter/AccountTransactionOrderTest.java
  18. 2
      plugin-api/build.gradle
  19. 7
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.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();
}

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; 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.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
@ -142,7 +143,8 @@ public class BlockTransactionSelector {
pendingTransaction -> { pendingTransaction -> {
final var res = evaluateTransaction(pendingTransaction); final var res = evaluateTransaction(pendingTransaction);
if (!res.selected()) { if (!res.selected()) {
transactionSelectionResults.updateNotSelected(pendingTransaction, res); transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), res);
} }
return res; return res;
}); });
@ -165,7 +167,7 @@ public class BlockTransactionSelector {
public TransactionSelectionResults evaluateTransactions(final List<Transaction> transactions) { public TransactionSelectionResults evaluateTransactions(final List<Transaction> transactions) {
transactions.forEach( transactions.forEach(
transaction -> { transaction -> {
final var res = evaluateTransaction(transaction); final var res = evaluateTransaction(new PendingTransaction.Local(transaction));
if (!res.selected()) { if (!res.selected()) {
transactionSelectionResults.updateNotSelected(transaction, res); transactionSelectionResults.updateNotSelected(transaction, res);
} }
@ -182,12 +184,16 @@ public class BlockTransactionSelector {
* the space remaining in the block. * the space remaining in the block.
* *
*/ */
private TransactionSelectionResult evaluateTransaction(final Transaction transaction) { private TransactionSelectionResult evaluateTransaction(
final PendingTransaction pendingTransaction) {
if (isCancelled.get()) { if (isCancelled.get()) {
throw new CancellationException("Cancelled during transaction selection."); throw new CancellationException("Cancelled during transaction selection.");
} }
TransactionSelectionResult selectionResult = evaluateTransactionPreProcessing(transaction); final Transaction transaction = pendingTransaction.getTransaction();
TransactionSelectionResult selectionResult =
evaluateTransactionPreProcessing(pendingTransaction);
if (!selectionResult.selected()) { if (!selectionResult.selected()) {
return selectionResult; return selectionResult;
} }
@ -209,7 +215,7 @@ public class BlockTransactionSelector {
blockSelectionContext.blobGasPrice()); blockSelectionContext.blobGasPrice());
var transactionWithProcessingContextResult = var transactionWithProcessingContextResult =
evaluateTransactionPostProcessing(transaction, effectiveResult); evaluateTransactionPostProcessing(pendingTransaction, effectiveResult);
if (!transactionWithProcessingContextResult.selected()) { if (!transactionWithProcessingContextResult.selected()) {
return transactionWithProcessingContextResult; return transactionWithProcessingContextResult;
} }
@ -243,16 +249,17 @@ public class BlockTransactionSelector {
* it then processes it through external selectors. If the transaction is selected by all * it then processes it through external selectors. If the transaction is selected by all
* selectors, it returns SELECTED. * 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. * @return The result of the transaction selection process.
*/ */
private TransactionSelectionResult evaluateTransactionPreProcessing( private TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction) { final PendingTransaction pendingTransaction) {
// Process the transaction through internal selectors // Process the transaction through internal selectors
for (var selector : transactionSelectors) { for (var selector : transactionSelectors) {
TransactionSelectionResult result = TransactionSelectionResult result =
selector.evaluateTransactionPreProcessing(transaction, transactionSelectionResults); selector.evaluateTransactionPreProcessing(
pendingTransaction, transactionSelectionResults);
// If the transaction is not selected by any internal selector, return the result // If the transaction is not selected by any internal selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) { if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result; return result;
@ -261,7 +268,8 @@ public class BlockTransactionSelector {
// Process the transaction through external selectors // Process the transaction through external selectors
for (var selector : externalTransactionSelectors) { 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 the transaction is not selected by any external selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) { if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result; 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 * whether the transaction should be included in a block. If the transaction is selected by all
* selectors, it returns SELECTED. * 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. * @param processingResult The result of the transaction processing.
* @return The result of the transaction selection process. * @return The result of the transaction selection process.
*/ */
private TransactionSelectionResult evaluateTransactionPostProcessing( private TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final TransactionProcessingResult processingResult) { final PendingTransaction pendingTransaction,
final TransactionProcessingResult processingResult) {
// Process the transaction through internal selectors // Process the transaction through internal selectors
for (var selector : transactionSelectors) { for (var selector : transactionSelectors) {
TransactionSelectionResult result = TransactionSelectionResult result =
selector.evaluateTransactionPostProcessing( selector.evaluateTransactionPostProcessing(
transaction, transactionSelectionResults, processingResult); pendingTransaction, transactionSelectionResults, processingResult);
// If the transaction is not selected by any selector, return the result // If the transaction is not selected by any selector, return the result
if (!result.equals(TransactionSelectionResult.SELECTED)) { if (!result.equals(TransactionSelectionResult.SELECTED)) {
return result; return result;

@ -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.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; 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.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; 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. * 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. * @param blockTransactionResults The results of other transaction evaluations in the same block.
* @return The result of the transaction evaluation * @return The result of the transaction evaluation
*/ */
public abstract TransactionSelectionResult evaluateTransactionPreProcessing( 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 * Evaluates a transaction considering other transactions in the same block and a transaction
* processing result. * 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 blockTransactionResults The results of other transaction evaluations in the same block.
* @param processingResult The result of transaction processing. * @param processingResult The result of transaction processing.
* @return The result of the transaction evaluation * @return The result of the transaction evaluation
*/ */
public abstract TransactionSelectionResult evaluateTransactionPostProcessing( public abstract TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults, final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult); final TransactionProcessingResult processingResult);
} }

@ -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.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Transaction; 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.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
@ -38,14 +39,14 @@ public class BlobPriceTransactionSelector extends AbstractTransactionSelector {
/** /**
* Evaluates a transaction considering its blob price. * 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. * @param ignored The results of other transaction evaluations in the same block.
* @return The result of the transaction selection. * @return The result of the transaction selection.
*/ */
@Override @Override
public TransactionSelectionResult evaluateTransactionPreProcessing( public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults ignored) { final PendingTransaction pendingTransaction, final TransactionSelectionResults ignored) {
if (transactionBlobPriceBelowMin(transaction)) { if (transactionBlobPriceBelowMin(pendingTransaction.getTransaction())) {
return TransactionSelectionResult.BLOB_PRICE_BELOW_CURRENT_MIN; return TransactionSelectionResult.BLOB_PRICE_BELOW_CURRENT_MIN;
} }
return TransactionSelectionResult.SELECTED; return TransactionSelectionResult.SELECTED;
@ -53,7 +54,7 @@ public class BlobPriceTransactionSelector extends AbstractTransactionSelector {
@Override @Override
public TransactionSelectionResult evaluateTransactionPostProcessing( public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults, final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) { final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here. // All necessary checks were done in the pre-processing method, so nothing to do here.

@ -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.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Transaction; 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.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; 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 * 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. * 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 * @param transactionSelectionResults The results of other transaction evaluations in the same
* block. * block.
* @return The result of the transaction selection. * @return The result of the transaction selection.
*/ */
@Override @Override
public TransactionSelectionResult evaluateTransactionPreProcessing( public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults transactionSelectionResults) { final TransactionSelectionResults transactionSelectionResults) {
if (transactionTooLargeForBlock(transaction, transactionSelectionResults)) { if (transactionTooLargeForBlock(
pendingTransaction.getTransaction(), transactionSelectionResults)) {
LOG.atTrace() LOG.atTrace()
.setMessage("Transaction {} too large to select for block creation") .setMessage("Transaction {} too large to select for block creation")
.addArgument(transaction::toTraceLog) .addArgument(pendingTransaction::toTraceLog)
.log(); .log();
if (blockOccupancyAboveThreshold(transactionSelectionResults)) { if (blockOccupancyAboveThreshold(transactionSelectionResults)) {
LOG.trace("Block occupancy above threshold, completing operation"); LOG.trace("Block occupancy above threshold, completing operation");
@ -68,7 +70,7 @@ public class BlockSizeTransactionSelector extends AbstractTransactionSelector {
@Override @Override
public TransactionSelectionResult evaluateTransactionPostProcessing( public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults, final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) { final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here. // All necessary checks were done in the pre-processing method, so nothing to do here.

@ -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.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Transaction; 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.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; 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 * Evaluates a transaction considering its price. If the transaction's current price is below the
* minimum, it returns a selection result indicating the reason. * 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. * @param ignored The results of other transaction evaluations in the same block.
* @return The result of the transaction selection. * @return The result of the transaction selection.
*/ */
@Override @Override
public TransactionSelectionResult evaluateTransactionPreProcessing( public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction, final TransactionSelectionResults ignored) { final PendingTransaction pendingTransaction, final TransactionSelectionResults ignored) {
if (transactionCurrentPriceBelowMin(transaction)) { if (transactionCurrentPriceBelowMin(pendingTransaction)) {
return TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN; return TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN;
} }
return TransactionSelectionResult.SELECTED; return TransactionSelectionResult.SELECTED;
@ -55,7 +56,7 @@ public class PriceTransactionSelector extends AbstractTransactionSelector {
@Override @Override
public TransactionSelectionResult evaluateTransactionPostProcessing( public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults, final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) { final TransactionProcessingResult processingResult) {
// All necessary checks were done in the pre-processing method, so nothing to do here. // 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. * 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. * @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 // 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 // that we do when accepting them in the pool are enough
if (transaction.getType().supports1559FeeMarket() 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 // 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 // only calculate at this time the current minimum price the transaction is willing to pay

@ -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.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Transaction; 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.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
@ -40,7 +41,8 @@ public class ProcessingResultTransactionSelector extends AbstractTransactionSele
@Override @Override
public TransactionSelectionResult evaluateTransactionPreProcessing( 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 // All checks depend on processingResult and will be done in the post-processing method, so
// nothing to do here. // nothing to do here.
return TransactionSelectionResult.SELECTED; 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. If the processing result is invalid, it determines the selection result for the invalid
* result. * 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 blockTransactionResults The results of other transaction evaluations in the same block.
* @param processingResult The processing result of the transaction. * @param processingResult The processing result of the transaction.
* @return The result of the transaction selection. * @return The result of the transaction selection.
*/ */
@Override @Override
public TransactionSelectionResult evaluateTransactionPostProcessing( public TransactionSelectionResult evaluateTransactionPostProcessing(
final Transaction transaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults, final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) { final TransactionProcessingResult processingResult) {
if (processingResult.isInvalid()) { if (processingResult.isInvalid()) {
return transactionSelectionResultForInvalidResult( return transactionSelectionResultForInvalidResult(
transaction, processingResult.getValidationResult()); pendingTransaction.getTransaction(), processingResult.getValidationResult());
} }
return TransactionSelectionResult.SELECTED; return TransactionSelectionResult.SELECTED;
} }

@ -552,10 +552,10 @@ public abstract class AbstractBlockTransactionSelectorTest {
final TransactionSelectorFactory transactionSelectorFactory = final TransactionSelectorFactory transactionSelectorFactory =
() -> () ->
(tx) -> { pendingTx -> {
if (tx.equals(notSelectedTransient)) if (pendingTx.getTransaction().equals(notSelectedTransient))
return TransactionSelectionResult.invalidTransient("transient"); return TransactionSelectionResult.invalidTransient("transient");
if (tx.equals(notSelectedInvalid)) if (pendingTx.getTransaction().equals(notSelectedInvalid))
return TransactionSelectionResult.invalid("invalid"); return TransactionSelectionResult.invalid("invalid");
return TransactionSelectionResult.SELECTED; return TransactionSelectionResult.SELECTED;
}; };
@ -572,7 +572,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
transactionSelectorFactory); transactionSelectorFactory);
transactionPool.addRemoteTransactions( transactionPool.addRemoteTransactions(
List.of(selected, notSelectedInvalid, notSelectedTransient)); List.of(selected, notSelectedTransient, notSelectedInvalid));
final TransactionSelectionResults transactionSelectionResults = final TransactionSelectionResults transactionSelectionResults =
selector.buildTransactionListForBlock(); selector.buildTransactionListForBlock();

@ -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);
}
}

@ -28,7 +28,8 @@ import java.util.concurrent.atomic.AtomicLong;
* Tracks the additional metadata associated with transactions to enable prioritization for mining * 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. * 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 NOT_INITIALIZED = -1;
static final int FRONTIER_BASE_MEMORY_SIZE = 944; static final int FRONTIER_BASE_MEMORY_SIZE = 944;
static final int ACCESS_LIST_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(); this.sequence = TRANSACTIONS_ADDED.getAndIncrement();
} }
@Override
public Transaction getTransaction() { public Transaction getTransaction() {
return transaction; return transaction;
} }
@ -72,12 +74,11 @@ public abstract class PendingTransaction {
return transaction.getSender(); return transaction.getSender();
} }
public abstract boolean isReceivedFromLocalSource();
public Hash getHash() { public Hash getHash() {
return transaction.getHash(); return transaction.getHash();
} }
@Override
public long getAddedAt() { public long getAddedAt() {
return addedAt; return addedAt;
} }
@ -184,6 +185,8 @@ public abstract class PendingTransaction {
+ addedAt + addedAt
+ ", sequence=" + ", sequence="
+ sequence + sequence
+ ", isLocal="
+ isReceivedFromLocalSource()
+ '}'; + '}';
} }
@ -192,6 +195,8 @@ public abstract class PendingTransaction {
+ sequence + sequence
+ ", addedAt: " + ", addedAt: "
+ addedAt + addedAt
+ ", isLocal="
+ isReceivedFromLocalSource()
+ ", " + ", "
+ transaction.toTraceLog() + transaction.toTraceLog()
+ "}"; + "}";

@ -88,6 +88,6 @@ public interface PendingTransactions {
@FunctionalInterface @FunctionalInterface
interface TransactionSelector { interface TransactionSelector {
TransactionSelectionResult evaluateTransaction(Transaction transaction); TransactionSelectionResult evaluateTransaction(PendingTransaction pendingTransaction);
} }
} }

@ -342,8 +342,7 @@ public class LayeredPendingTransactions implements PendingTransactions {
.forEach( .forEach(
candidatePendingTx -> { candidatePendingTx -> {
alreadyChecked.add(candidatePendingTx.getHash()); alreadyChecked.add(candidatePendingTx.getHash());
final var res = final var res = selector.evaluateTransaction(candidatePendingTx);
selector.evaluateTransaction(candidatePendingTx.getTransaction());
LOG.atTrace() LOG.atTrace()
.setMessage("Selection result {} for transaction {}") .setMessage("Selection result {} for transaction {}")

@ -22,7 +22,6 @@ import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedRes
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; 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.BlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
@ -259,16 +258,15 @@ public abstract class AbstractPendingTransactionsSorter implements PendingTransa
accountTransactions.computeIfAbsent( accountTransactions.computeIfAbsent(
highestPriorityPendingTransaction.getSender(), this::createSenderTransactionOrder); highestPriorityPendingTransaction.getSender(), this::createSenderTransactionOrder);
for (final Transaction transactionToProcess : for (final PendingTransaction transactionToProcess :
accountTransactionOrder.transactionsToProcess( accountTransactionOrder.transactionsToProcess(highestPriorityPendingTransaction)) {
highestPriorityPendingTransaction.getTransaction())) {
final TransactionSelectionResult result = final TransactionSelectionResult result =
selector.evaluateTransaction(transactionToProcess); selector.evaluateTransaction(transactionToProcess);
if (result.discard()) { if (result.discard()) {
transactionsToRemove.add(transactionToProcess); transactionsToRemove.add(transactionToProcess.getTransaction());
transactionsToRemove.addAll( transactionsToRemove.addAll(
signalInvalidAndGetDependentTransactions(transactionToProcess)); signalInvalidAndGetDependentTransactions(transactionToProcess.getTransaction()));
} }
if (result.stop()) { if (result.stop()) {
@ -283,10 +281,7 @@ public abstract class AbstractPendingTransactionsSorter implements PendingTransa
private AccountTransactionOrder createSenderTransactionOrder(final Address address) { private AccountTransactionOrder createSenderTransactionOrder(final Address address) {
return new AccountTransactionOrder( return new AccountTransactionOrder(
transactionsBySender transactionsBySender.get(address).streamPendingTransactions());
.get(address)
.streamPendingTransactions()
.map(PendingTransaction::getTransaction));
} }
private TransactionAddedResult addTransactionForSenderAndNonce( private TransactionAddedResult addTransactionForSenderAndNonce(

@ -12,7 +12,9 @@
* *
* SPDX-License-Identifier: Apache-2.0 * 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.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@ -23,12 +25,14 @@ import java.util.stream.Stream;
public class AccountTransactionOrder { public class AccountTransactionOrder {
private static final Comparator<Transaction> SORT_BY_NONCE = private static final Comparator<PendingTransaction> SORT_BY_NONCE =
Comparator.comparing(Transaction::getNonce); Comparator.comparing(PendingTransaction::getNonce);
private final NavigableSet<Transaction> transactionsForSender = new TreeSet<>(SORT_BY_NONCE); private final NavigableSet<PendingTransaction> transactionsForSender =
private final NavigableSet<Transaction> deferredTransactions = new TreeSet<>(SORT_BY_NONCE); new TreeSet<>(SORT_BY_NONCE);
private final NavigableSet<PendingTransaction> deferredTransactions =
new TreeSet<>(SORT_BY_NONCE);
public AccountTransactionOrder(final Stream<Transaction> senderTransactions) { public AccountTransactionOrder(final Stream<PendingTransaction> senderTransactions) {
senderTransactions.forEach(this.transactionsForSender::add); senderTransactions.forEach(this.transactionsForSender::add);
} }
@ -44,14 +48,14 @@ public class AccountTransactionOrder {
* order. Must be from the sender this instance is ordering. * 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. * @return the transactions from this sender that are now due to be processed, in order.
*/ */
public Iterable<Transaction> transactionsToProcess( public Iterable<PendingTransaction> transactionsToProcess(
final Transaction nextTransactionInPriorityOrder) { final PendingTransaction nextTransactionInPriorityOrder) {
deferredTransactions.add(nextTransactionInPriorityOrder); deferredTransactions.add(nextTransactionInPriorityOrder);
final List<Transaction> transactionsToApply = new ArrayList<>(); final List<PendingTransaction> transactionsToApply = new ArrayList<>();
while (!deferredTransactions.isEmpty() while (!deferredTransactions.isEmpty()
&& !transactionsForSender.isEmpty() && !transactionsForSender.isEmpty()
&& deferredTransactions.first().equals(transactionsForSender.first())) { && deferredTransactions.first().equals(transactionsForSender.first())) {
final Transaction transaction = deferredTransactions.first(); final PendingTransaction transaction = deferredTransactions.first();
transactionsToApply.add(transaction); transactionsToApply.add(transaction);
deferredTransactions.remove(transaction); deferredTransactions.remove(transaction);
transactionsForSender.remove(transaction); transactionsForSender.remove(transaction);

@ -302,8 +302,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> parsedTransactions = new ArrayList<>(); final List<Transaction> parsedTransactions = new ArrayList<>();
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTX -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTX.getTransaction());
return selectionResult; return selectionResult;
}); });
@ -322,8 +322,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> parsedTransactions = new ArrayList<>(); final List<Transaction> parsedTransactions = new ArrayList<>();
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -342,8 +342,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> parsedTransactions = new ArrayList<>(); final List<Transaction> parsedTransactions = new ArrayList<>();
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -363,8 +363,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> iterationOrder = new ArrayList<>(3); final List<Transaction> iterationOrder = new ArrayList<>(3);
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -387,10 +387,10 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> iterationOrder = new ArrayList<>(3); final List<Transaction> iterationOrder = new ArrayList<>(3);
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
// pretending that the 2nd tx of the 1st sender is not selected // 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 // 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<Transaction> iterationOrder = new ArrayList<>(2); final List<Transaction> iterationOrder = new ArrayList<>(2);
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -435,8 +435,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> parsedTransactions = new ArrayList<>(1); final List<Transaction> parsedTransactions = new ArrayList<>(1);
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name()); return TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name());
}); });
@ -455,8 +455,8 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
final List<Transaction> parsedTransactions = new ArrayList<>(1); final List<Transaction> parsedTransactions = new ArrayList<>(1);
pendingTransactions.selectTransactions( pendingTransactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return TransactionSelectionResult.invalidTransient( return TransactionSelectionResult.invalidTransient(
GAS_PRICE_BELOW_CURRENT_BASE_FEE.name()); GAS_PRICE_BELOW_CURRENT_BASE_FEE.name());
}); });

@ -315,8 +315,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> parsedTransactions = Lists.newArrayList(); final List<Transaction> parsedTransactions = Lists.newArrayList();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD; return TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD;
}); });
@ -331,8 +331,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> parsedTransactions = Lists.newArrayList(); final List<Transaction> parsedTransactions = Lists.newArrayList();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -351,8 +351,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> parsedTransactions = Lists.newArrayList(); final List<Transaction> parsedTransactions = Lists.newArrayList();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -366,8 +366,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> parsedTransactions = Lists.newArrayList(); final List<Transaction> parsedTransactions = Lists.newArrayList();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
parsedTransactions.add(transaction); parsedTransactions.add(pendingTx.getTransaction());
return TransactionSelectionResult.invalid( return TransactionSelectionResult.invalid(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name()); TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name());
}); });
@ -535,8 +535,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> iterationOrder = new ArrayList<>(); final List<Transaction> iterationOrder = new ArrayList<>();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -553,8 +553,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> iterationOrder = new ArrayList<>(); final List<Transaction> iterationOrder = new ArrayList<>();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });
@ -575,8 +575,8 @@ public abstract class AbstractPendingTransactionsTestBase {
final List<Transaction> iterationOrder = new ArrayList<>(); final List<Transaction> iterationOrder = new ArrayList<>();
transactions.selectTransactions( transactions.selectTransactions(
transaction -> { pendingTx -> {
iterationOrder.add(transaction); iterationOrder.add(pendingTx.getTransaction());
return SELECTED; return SELECTED;
}); });

@ -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);
}
}

@ -69,7 +69,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) { tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought" description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files files = sourceSets.main.allJava.files
knownHash = 'ON5/4jw14IPAL/Civ3ld6tvwrLsGS9eI38w5C0xRzdY=' knownHash = 'gfZY0boUMYJoAHwou3eEhcz7A/xFvJKnjMUONZ6hY3I='
} }
check.dependsOn('checkAPIChanges') check.dependsOn('checkAPIChanges')

@ -15,7 +15,7 @@
package org.hyperledger.besu.plugin.services.txselection; 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.Unstable;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; 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 * 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. * 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 * @return TransactionSelectionResult that indicates whether to include the transaction
*/ */
TransactionSelectionResult evaluateTransactionPreProcessing(Transaction transaction); TransactionSelectionResult evaluateTransactionPreProcessing(
PendingTransaction pendingTransaction);
} }

Loading…
Cancel
Save