diff --git a/CHANGELOG.md b/CHANGELOG.md index 225b1efc382..bf9338d4f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Additions and Improvements - Extend `Blockchain` service [#6592](https://github.com/hyperledger/besu/pull/6592) - RocksDB database metadata refactoring [#6555](https://github.com/hyperledger/besu/pull/6555) +- Make layered txpool aware of minGasPrice and minPriorityFeePerGas dynamic options [#6611](https://github.com/hyperledger/besu/pull/6611) ### Bug fixes diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 1a74e4996e2..3dd221514a6 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -710,7 +710,8 @@ public BesuController build() { syncState, transactionPoolConfiguration, pluginTransactionValidatorFactory, - besuComponent.map(BesuComponent::getBlobCache).orElse(new BlobCache())); + besuComponent.map(BesuComponent::getBlobCache).orElse(new BlobCache()), + miningParameters); final List peerValidators = createPeerValidators(protocolSchedule); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 87b6255b593..8b21fa215fa 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -167,7 +168,8 @@ public void setUp() { syncState, txPoolConfig, null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); serviceImpl = new BesuEventsImpl(blockchain, blockBroadcaster, transactionPool, syncState); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java index 9f061facac5..b6c9c14a632 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java @@ -132,7 +132,8 @@ public abstract class AbstractIsolationTests { new EndLayer(txPoolMetrics), txPoolMetrics, transactionReplacementTester, - new BlobCache())); + new BlobCache(), + MiningParameters.newDefault())); protected final List accounts = GenesisConfigFile.development() diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java index 253d37a4758..0f9aaa002db 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactory.java @@ -17,6 +17,7 @@ import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; @@ -55,7 +56,8 @@ public static TransactionPool createTransactionPool( final SyncState syncState, final TransactionPoolConfiguration transactionPoolConfiguration, final PluginTransactionValidatorFactory pluginTransactionValidatorFactory, - final BlobCache blobCache) { + final BlobCache blobCache, + final MiningParameters miningParameters) { final TransactionPoolMetrics metrics = new TransactionPoolMetrics(metricsSystem); @@ -78,7 +80,8 @@ public static TransactionPool createTransactionPool( transactionsMessageSender, newPooledTransactionHashesMessageSender, pluginTransactionValidatorFactory, - blobCache); + blobCache, + miningParameters); } static TransactionPool createTransactionPool( @@ -93,7 +96,8 @@ static TransactionPool createTransactionPool( final TransactionsMessageSender transactionsMessageSender, final NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender, final PluginTransactionValidatorFactory pluginTransactionValidatorFactory, - final BlobCache blobCache) { + final BlobCache blobCache, + final MiningParameters miningParameters) { final TransactionPool transactionPool = new TransactionPool( @@ -104,7 +108,8 @@ static TransactionPool createTransactionPool( clock, metrics, transactionPoolConfiguration, - blobCache), + blobCache, + miningParameters), protocolSchedule, protocolContext, new TransactionBroadcaster( @@ -233,7 +238,8 @@ private static PendingTransactions createPendingTransactions( final Clock clock, final TransactionPoolMetrics metrics, final TransactionPoolConfiguration transactionPoolConfiguration, - final BlobCache blobCache) { + final BlobCache blobCache, + final MiningParameters miningParameters) { boolean isFeeMarketImplementBaseFee = protocolSchedule.anyMatch( @@ -246,7 +252,8 @@ private static PendingTransactions createPendingTransactions( metrics, transactionPoolConfiguration, isFeeMarketImplementBaseFee, - blobCache); + blobCache, + miningParameters); } else { return createPendingTransactionSorter( protocolContext, @@ -284,7 +291,8 @@ private static PendingTransactions createLayeredPendingTransactions( final TransactionPoolMetrics metrics, final TransactionPoolConfiguration transactionPoolConfiguration, final boolean isFeeMarketImplementBaseFee, - final BlobCache blobCache) { + final BlobCache blobCache, + final MiningParameters miningParameters) { final TransactionPoolReplacementHandler transactionReplacementHandler = new TransactionPoolReplacementHandler(transactionPoolConfiguration.getPriceBump()); @@ -327,7 +335,8 @@ private static PendingTransactions createLayeredPendingTransactions( metrics, transactionReplacementTester, feeMarket, - blobCache); + blobCache, + miningParameters); } else { pendingTransactionsSorter = new GasPricePrioritizedTransactions( @@ -335,7 +344,8 @@ private static PendingTransactions createLayeredPendingTransactions( readyTransactions, metrics, transactionReplacementTester, - blobCache); + blobCache, + miningParameters); } return new LayeredPendingTransactions(transactionPoolConfiguration, pendingTransactionsSorter); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactions.java index 7d59f40afb7..b796eefaca4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactions.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.transactions.layered; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult; @@ -36,6 +37,7 @@ */ public abstract class AbstractPrioritizedTransactions extends AbstractSequentialTransactionsLayer { protected final TreeSet orderByFee; + protected final MiningParameters miningParameters; public AbstractPrioritizedTransactions( final TransactionPoolConfiguration poolConfig, @@ -43,9 +45,11 @@ public AbstractPrioritizedTransactions( final TransactionPoolMetrics metrics, final BiFunction transactionReplacementTester, - final BlobCache blobCache) { + final BlobCache blobCache, + final MiningParameters miningParameters) { super(poolConfig, prioritizedTransactions, transactionReplacementTester, metrics, blobCache); this.orderByFee = new TreeSet<>(this::compareByFee); + this.miningParameters = miningParameters; } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java index c1e9bec63d2..e1d10e9ee2a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactions.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; @@ -47,8 +48,10 @@ public BaseFeePrioritizedTransactions( final BiFunction transactionReplacementTester, final FeeMarket feeMarket, - final BlobCache blobCache) { - super(poolConfig, nextLayer, metrics, transactionReplacementTester, blobCache); + final BlobCache blobCache, + final MiningParameters miningParameters) { + super( + poolConfig, nextLayer, metrics, transactionReplacementTester, blobCache, miningParameters); this.nextBlockBaseFee = Optional.of(calculateNextBlockBaseFee(feeMarket, chainHeadHeaderSupplier.get())); } @@ -146,11 +149,34 @@ private Wei calculateNextBlockBaseFee(final FeeMarket feeMarket, final BlockHead @Override protected boolean promotionFilter(final PendingTransaction pendingTransaction) { - return nextBlockBaseFee - .map( - baseFee -> - pendingTransaction.getTransaction().getMaxGasPrice().greaterOrEqualThan(baseFee)) - .orElse(false); + // check if the tx is willing to pay at least the base fee + if (nextBlockBaseFee + .map(pendingTransaction.getTransaction().getMaxGasPrice()::lessThan) + .orElse(true)) { + return false; + } + + // priority txs are promoted even if they pay less + if (!pendingTransaction.hasPriority()) { + // check if max fee per gas is higher than the min gas price + if (pendingTransaction + .getTransaction() + .getMaxGasPrice() + .lessThan(miningParameters.getMinTransactionGasPrice())) { + return false; + } + + // check if enough priority fee is paid + if (!miningParameters.getMinPriorityFeePerGas().equals(Wei.ZERO)) { + final Wei priorityFeePerGas = + pendingTransaction.getTransaction().getEffectivePriorityFeePerGas(nextBlockBaseFee); + if (priorityFeePerGas.lessThan(miningParameters.getMinPriorityFeePerGas())) { + return false; + } + } + } + + return true; } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactions.java index c6c402a1108..e6a939d660e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactions.java @@ -17,6 +17,7 @@ import static java.util.Comparator.comparing; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; @@ -39,8 +40,10 @@ public GasPricePrioritizedTransactions( final TransactionPoolMetrics metrics, final BiFunction transactionReplacementTester, - final BlobCache blobCache) { - super(poolConfig, nextLayer, metrics, transactionReplacementTester, blobCache); + final BlobCache blobCache, + final MiningParameters miningParameters) { + super( + poolConfig, nextLayer, metrics, transactionReplacementTester, blobCache, miningParameters); } @Override @@ -58,7 +61,12 @@ protected void internalBlockAdded(final BlockHeader blockHeader, final FeeMarket @Override protected boolean promotionFilter(final PendingTransaction pendingTransaction) { - return true; + return pendingTransaction.hasPriority() + || pendingTransaction + .getTransaction() + .getGasPrice() + .map(miningParameters.getMinTransactionGasPrice()::lessThan) + .orElse(false); } @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index c05bdcb1865..7602de7ab69 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; @@ -1118,7 +1119,8 @@ public void transactionMessagesGoToTheCorrectExecutor() { new SyncState(blockchain, ethManager.ethContext().getEthPeers()), TransactionPoolConfiguration.DEFAULT, null, - new BlobCache()) + new BlobCache(), + MiningParameters.newDefault()) .setEnabled(); // Send just a transaction message. diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index 3ea2dc27f3c..5b39672ff04 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.EthProtocol; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -136,7 +137,8 @@ public void setupTest() { syncState, TransactionPoolConfiguration.DEFAULT, null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); transactionPool.setEnabled(); ethProtocolManager = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index 6d6ff994b56..62a2e615b07 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -128,6 +128,7 @@ public abstract class AbstractTransactionPoolTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); protected static final Wei BASE_FEE_FLOOR = Wei.of(7L); + protected static final Wei DEFAULT_MIN_GAS_PRICE = Wei.of(50L); @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected TransactionValidatorFactory transactionValidatorFactory; @@ -455,6 +456,7 @@ public void shouldNotReAddTransactionsThatAreInBothForksWhenReorgHappens() { } @Test + @EnabledIf("isBaseFeeMarket") public void shouldReAddBlobTxsWhenReorgHappens() { givenTransactionIsValid(transaction0); givenTransactionIsValid(transaction1); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index ff624baa761..674dec68530 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; import org.hyperledger.besu.ethereum.eth.EthProtocol; @@ -166,7 +167,8 @@ public boolean isMessagePermitted(final EnodeURL destinationEnode, final int cod syncState, TransactionPoolConfiguration.DEFAULT, null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); final EthProtocolManager ethProtocolManager = new EthProtocolManager( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index 3d97f703c18..66419f62525 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -251,7 +252,8 @@ private void setupInitialSyncPhase(final boolean hasInitialSyncPhase) { transactionsMessageSender, newPooledTransactionHashesMessageSender, null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); ethProtocolManager = new EthProtocolManager( @@ -359,7 +361,8 @@ private TransactionPool createTransactionPool( .build()) .build(), null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); txPool.setEnabled(); return txPool; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactionsTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactionsTestBase.java index 86741de9146..10e40a6ed1f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactionsTestBase.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractPrioritizedTransactionsTestBase.java @@ -16,9 +16,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ADDED; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.DROPPED; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; @@ -27,7 +29,6 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolReplacementHandler; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -40,19 +41,26 @@ public abstract class AbstractPrioritizedTransactionsTestBase extends BaseTransa protected static final int MAX_TRANSACTIONS = 5; protected final TransactionPoolMetrics txPoolMetrics = new TransactionPoolMetrics(metricsSystem); protected final EvictCollectorLayer evictCollector = new EvictCollectorLayer(txPoolMetrics); + protected final MiningParameters miningParameters = + MiningParameters.newDefault() + .setMinTransactionGasPrice(DEFAULT_MIN_GAS_PRICE) + .setMinPriorityFeePerGas(DEFAULT_MIN_PRIORITY_FEE); protected AbstractPrioritizedTransactions transactions = getSorter( ImmutableTransactionPoolConfiguration.builder() .maxPrioritizedTransactions(MAX_TRANSACTIONS) .maxFutureBySender(MAX_TRANSACTIONS) - .build()); + .build(), + miningParameters); - private AbstractPrioritizedTransactions getSorter(final TransactionPoolConfiguration poolConfig) { + private AbstractPrioritizedTransactions getSorter( + final TransactionPoolConfiguration poolConfig, final MiningParameters miningParameters) { return getSorter( poolConfig, evictCollector, txPoolMetrics, - (pt1, pt2) -> transactionReplacementTester(poolConfig, pt1, pt2)); + (pt1, pt2) -> transactionReplacementTester(poolConfig, pt1, pt2), + miningParameters); } abstract AbstractPrioritizedTransactions getSorter( @@ -60,7 +68,8 @@ abstract AbstractPrioritizedTransactions getSorter( final TransactionsLayer nextLayer, final TransactionPoolMetrics txPoolMetrics, final BiFunction - transactionReplacementTester); + transactionReplacementTester, + final MiningParameters miningParameters); abstract BlockHeader mockBlockHeader(); @@ -80,13 +89,13 @@ public void prioritizeLocalTransactionThenValue() { assertThat(prioritizeTransaction(localTransaction)).isEqualTo(ADDED); final List remoteTxs = new ArrayList<>(); - TransactionAddedResult prioritizeResult = null; + TransactionAddedResult prioritizeResult; for (int i = 0; i < MAX_TRANSACTIONS; i++) { final PendingTransaction highValueRemoteTx = createRemotePendingTransaction( createTransaction( 0, - Wei.of(BigInteger.valueOf(100).pow(i)), + Wei.of(DEFAULT_MIN_GAS_PRICE.multiply(2).toBigInteger().pow(i + 1)), SIGNATURE_ALGORITHM.get().generateKeyPair())); remoteTxs.add(highValueRemoteTx); prioritizeResult = prioritizeTransaction(highValueRemoteTx); @@ -123,6 +132,25 @@ public void shouldStartDroppingLocalTransactionsWhenPoolIsFullOfLocalTransaction assertTransactionNotPrioritized(lastLocalTransaction); } + @Test + public void txBelowCurrentMineableMinGasPriceIsNotPrioritized() { + final PendingTransaction lowGasPriceTx = + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.subtract(1), KEYS1)); + assertThat(prioritizeTransaction(lowGasPriceTx)).isEqualTo(DROPPED); + assertEvicted(lowGasPriceTx); + assertTransactionNotPrioritized(lowGasPriceTx); + } + + @Test + public void txWithPriorityBelowCurrentMineableMinGasPriceIsPrioritized() { + final PendingTransaction lowGasPriceTx = + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.subtract(1), KEYS1), true); + assertThat(prioritizeTransaction(lowGasPriceTx)).isEqualTo(ADDED); + assertTransactionPrioritized(lowGasPriceTx); + } + protected void shouldPrioritizeValueThenTimeAddedToPool( final Iterator lowValueTxSupplier, final PendingTransaction highValueTx, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java index 4529f7f36e1..31785fa1898 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseFeePrioritizedTransactionsTest.java @@ -14,8 +14,11 @@ */ package org.hyperledger.besu.ethereum.eth.transactions.layered; +import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.datatypes.TransactionType.EIP1559; import static org.hyperledger.besu.datatypes.TransactionType.FRONTIER; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ADDED; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.DROPPED; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -23,6 +26,7 @@ import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; @@ -33,6 +37,7 @@ import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Random; import java.util.function.BiFunction; @@ -42,7 +47,7 @@ import org.junit.jupiter.api.Test; public class BaseFeePrioritizedTransactionsTest extends AbstractPrioritizedTransactionsTestBase { - + private static final FeeMarket EIP1559_FEE_MARKET = FeeMarket.london(0L); private static final Random randomizeTxType = new Random(); @Override @@ -51,7 +56,8 @@ AbstractPrioritizedTransactions getSorter( final TransactionsLayer nextLayer, final TransactionPoolMetrics txPoolMetrics, final BiFunction - transactionReplacementTester) { + transactionReplacementTester, + final MiningParameters miningParameters) { return new BaseFeePrioritizedTransactions( poolConfig, @@ -59,14 +65,19 @@ AbstractPrioritizedTransactions getSorter( nextLayer, txPoolMetrics, transactionReplacementTester, - FeeMarket.london(0L), - new BlobCache()); + EIP1559_FEE_MARKET, + new BlobCache(), + miningParameters); } @Override protected BlockHeader mockBlockHeader() { + return mockBlockHeader(Wei.ONE); + } + + private BlockHeader mockBlockHeader(final Wei baseFee) { final BlockHeader blockHeader = mock(BlockHeader.class); - when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ONE)); + when(blockHeader.getBaseFee()).thenReturn(Optional.of(baseFee)); return blockHeader; } @@ -116,7 +127,8 @@ public void shouldPrioritizeEffectivePriorityFeeThenTimeAddedToPoolOnMixedTypes( final var nextBlockBaseFee = Optional.of(Wei.ONE); final PendingTransaction highGasPriceTransaction = - createRemotePendingTransaction(createTransaction(0, Wei.of(100), KEYS1)); + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.multiply(2), KEYS1)); final List lowValueTxs = IntStream.range(0, MAX_TRANSACTIONS) @@ -124,7 +136,9 @@ public void shouldPrioritizeEffectivePriorityFeeThenTimeAddedToPoolOnMixedTypes( i -> new PendingTransaction.Remote( createTransaction( - 0, Wei.of(10), SIGNATURE_ALGORITHM.get().generateKeyPair()))) + 0, + DEFAULT_MIN_GAS_PRICE.add(1), + SIGNATURE_ALGORITHM.get().generateKeyPair()))) .collect(Collectors.toUnmodifiableList()); final var lowestPriorityFee = @@ -151,10 +165,34 @@ public void shouldPrioritizeEffectivePriorityFeeThenTimeAddedToPoolOnMixedTypes( lowValueTxs.iterator(), highGasPriceTransaction, firstLowValueTx); } + @Test + public void txBelowCurrentMineableMinPriorityFeeIsNotPrioritized() { + setBaseFee(DEFAULT_MIN_GAS_PRICE.subtract(2)); + miningParameters.setMinPriorityFeePerGas(Wei.of(5)); + final PendingTransaction lowPriorityFeeTx = + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.subtract(1), KEYS1)); + assertThat(prioritizeTransaction(lowPriorityFeeTx)).isEqualTo(DROPPED); + assertEvicted(lowPriorityFeeTx); + assertTransactionNotPrioritized(lowPriorityFeeTx); + } + + @Test + public void txWithPriorityBelowCurrentMineableMinPriorityFeeIsPrioritized() { + setBaseFee(DEFAULT_MIN_GAS_PRICE.subtract(2)); + miningParameters.setMinPriorityFeePerGas(Wei.of(5)); + final PendingTransaction lowGasPriceTx = + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.subtract(1), KEYS1), true); + assertThat(prioritizeTransaction(lowGasPriceTx)).isEqualTo(ADDED); + assertTransactionPrioritized(lowGasPriceTx); + } + private void shouldPrioritizePriorityFeeThenTimeAddedToPoolSameTypeTxs( final TransactionType transactionType) { final PendingTransaction highGasPriceTransaction = - createRemotePendingTransaction(createTransaction(0, Wei.of(100), KEYS1)); + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.multiply(20), KEYS1)); final var lowValueTxs = IntStream.range(0, MAX_TRANSACTIONS) @@ -164,7 +202,7 @@ private void shouldPrioritizePriorityFeeThenTimeAddedToPoolSameTypeTxs( createTransaction( transactionType, 0, - Wei.of(10), + DEFAULT_MIN_GAS_PRICE.add(1), 0, SIGNATURE_ALGORITHM.get().generateKeyPair()))) .collect(Collectors.toUnmodifiableList()); @@ -172,4 +210,8 @@ private void shouldPrioritizePriorityFeeThenTimeAddedToPoolSameTypeTxs( shouldPrioritizeValueThenTimeAddedToPool( lowValueTxs.iterator(), highGasPriceTransaction, lowValueTxs.get(0)); } + + private void setBaseFee(final Wei baseFee) { + transactions.blockAdded(EIP1559_FEE_MARKET, mockBlockHeader(baseFee), Map.of()); + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java index 0d69dac4faa..160c60c66d9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java @@ -54,7 +54,8 @@ public class BaseTransactionPoolTest { protected static final KeyPair KEYS2 = SIGNATURE_ALGORITHM.get().generateKeyPair(); protected static final Address SENDER1 = Util.publicKeyToAddress(KEYS1.getPublicKey()); protected static final Address SENDER2 = Util.publicKeyToAddress(KEYS2.getPublicKey()); - + protected static final Wei DEFAULT_MIN_GAS_PRICE = Wei.of(50); + protected static final Wei DEFAULT_MIN_PRIORITY_FEE = Wei.ZERO; private static final Random randomizeTxType = new Random(); protected final Transaction transaction0 = createTransaction(0); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactionsTest.java index 89e986678ff..c3aa720a618 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/GasPricePrioritizedTransactionsTest.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; @@ -42,10 +43,16 @@ AbstractPrioritizedTransactions getSorter( final TransactionsLayer nextLayer, final TransactionPoolMetrics txPoolMetrics, final BiFunction - transactionReplacementTester) { + transactionReplacementTester, + final MiningParameters miningParameters) { return new GasPricePrioritizedTransactions( - poolConfig, nextLayer, txPoolMetrics, transactionReplacementTester, new BlobCache()); + poolConfig, + nextLayer, + txPoolMetrics, + transactionReplacementTester, + new BlobCache(), + miningParameters); } @Override @@ -80,11 +87,14 @@ public void shouldPrioritizeGasPriceThenTimeAddedToPool() { i -> createRemotePendingTransaction( createTransaction( - 0, Wei.of(10), SIGNATURE_ALGORITHM.get().generateKeyPair()))) + 0, + DEFAULT_MIN_GAS_PRICE.add(1), + SIGNATURE_ALGORITHM.get().generateKeyPair()))) .toList(); final PendingTransaction highGasPriceTransaction = - createRemotePendingTransaction(createTransaction(0, Wei.of(100), KEYS1)); + createRemotePendingTransaction( + createTransaction(0, DEFAULT_MIN_GAS_PRICE.multiply(2), KEYS1)); shouldPrioritizeValueThenTimeAddedToPool( lowValueTxs.iterator(), highGasPriceTransaction, lowValueTxs.get(0)); 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 9f86cfc9207..1984c82c7d1 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 @@ -39,6 +39,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; @@ -136,7 +137,8 @@ private CreatedLayers createLayers(final TransactionPoolConfiguration poolConfig txPoolMetrics, transactionReplacementTester, FeeMarket.london(0L), - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault().setMinTransactionGasPrice(DEFAULT_MIN_GAS_PRICE)); return new CreatedLayers( prioritizedTransactions, readyTransactions, sparseTransactions, evictCollector); } @@ -216,7 +218,7 @@ public void evictTransactionsWhenSizeLimitExceeded() { final var tx = createTransaction( i, - Wei.of((i + 1) * 100L), + DEFAULT_MIN_GAS_PRICE.multiply(2 * (i + 1)), (int) poolConf.getPendingTransactionsLayerMaxCapacityBytes() + 1, SIGNATURE_ALGORITHM.get().generateKeyPair()); pendingTransactions.addTransaction(createRemotePendingTransaction(tx), Optional.of(sender)); @@ -229,7 +231,7 @@ public void evictTransactionsWhenSizeLimitExceeded() { final Transaction lastBigTx = createTransaction( 0, - Wei.of(100_000L), + DEFAULT_MIN_GAS_PRICE.multiply(1000), (int) poolConf.getPendingTransactionsLayerMaxCapacityBytes(), SIGNATURE_ALGORITHM.get().generateKeyPair()); final Account lastSender = mock(Account.class); @@ -458,8 +460,10 @@ public void notForceNonceOrderWhenSendersDiffer() { final Account sender2 = mock(Account.class); when(sender2.getNonce()).thenReturn(1L); - final Transaction transactionSender1 = createTransaction(0, Wei.of(100), KEYS1); - final Transaction transactionSender2 = createTransaction(1, Wei.of(200), KEYS2); + final Transaction transactionSender1 = + createTransaction(0, DEFAULT_MIN_GAS_PRICE.multiply(2), KEYS1); + final Transaction transactionSender2 = + createTransaction(1, DEFAULT_MIN_GAS_PRICE.multiply(4), KEYS2); pendingTransactions.addTransaction( createLocalPendingTransaction(transactionSender1), Optional.empty()); @@ -523,9 +527,9 @@ public void returnEmptyOptionalAsMaximumNonceWhenNoTransactionsPresent() { @Test public void replaceTransactionWithSameSenderAndNonce() { - final Transaction transaction1 = createTransaction(0, Wei.of(200), KEYS1); + final Transaction transaction1 = createTransaction(0, DEFAULT_MIN_GAS_PRICE.multiply(4), KEYS1); final Transaction transaction1b = createTransactionReplacement(transaction1, KEYS1); - final Transaction transaction2 = createTransaction(1, Wei.of(100), KEYS1); + final Transaction transaction2 = createTransaction(1, DEFAULT_MIN_GAS_PRICE.multiply(2), KEYS1); assertThat( pendingTransactions.addTransaction( createRemotePendingTransaction(transaction1), Optional.empty())) @@ -646,8 +650,8 @@ public void replaceTransactionWithSameSenderAndNonce_multipleReplacements() { @Test public void notReplaceTransactionWithSameSenderAndNonceWhenGasPriceIsLower() { - final Transaction transaction1 = createTransaction(0, Wei.of(2)); - final Transaction transaction1b = createTransaction(0, Wei.ONE); + final Transaction transaction1 = createTransaction(0, DEFAULT_MIN_GAS_PRICE.add(1)); + final Transaction transaction1b = createTransaction(0, DEFAULT_MIN_GAS_PRICE); assertThat( pendingTransactions.addTransaction( createRemotePendingTransaction(transaction1), Optional.empty())) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolBaseFeeTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolBaseFeeTest.java index b70f3c24ac5..61d513e447b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolBaseFeeTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolBaseFeeTest.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; @@ -46,7 +47,8 @@ protected AbstractPrioritizedTransactions createPrioritizedTransactions( txPoolMetrics, transactionReplacementTester, FeeMarket.london(0L), - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); } @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolGasPriceTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolGasPriceTest.java index e0066e03703..296219c90fc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolGasPriceTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredTransactionPoolGasPriceTest.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; @@ -39,7 +40,12 @@ protected AbstractPrioritizedTransactions createPrioritizedTransactions( final BiFunction transactionReplacementTester) { return new GasPricePrioritizedTransactions( - poolConfig, nextLayer, txPoolMetrics, transactionReplacementTester, new BlobCache()); + poolConfig, + nextLayer, + txPoolMetrics, + transactionReplacementTester, + new BlobCache(), + MiningParameters.newDefault()); } @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java index 7a22683ec42..d7874cb46a8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; @@ -94,7 +95,8 @@ public class LayersTest extends BaseTransactionPoolTest { txPoolMetrics, this::transactionReplacementTester, FeeMarket.london(0L), - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); private final LayeredPendingTransactions pendingTransactions = new LayeredPendingTransactions(poolConfig, prioritizedTransactions); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/ReplayTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/ReplayTest.java index 10595b6fd7a..0c0aa346b49 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/ReplayTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/ReplayTest.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; @@ -202,7 +203,8 @@ private BaseFeePrioritizedTransactions createLayers( txPoolMetrics, txReplacementTester, baseFeeMarket, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); } // ToDo: commented since not always working, needs fix diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index a78e689bcf4..c927b6f692d 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -256,7 +256,8 @@ private boolean buildContext( syncState, transactionPoolConfiguration, null, - new BlobCache()); + new BlobCache(), + MiningParameters.newDefault()); if (LOG.isTraceEnabled()) { LOG.trace("Genesis Block {} ", genesisState.getBlock());