Add transaction selector based on min priority fee parameter (#6083)

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
pull/6114/head
Gabriel-Trintinalia 1 year ago committed by GitHub
parent 236779d3ce
commit 41b95758b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 2
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java
  3. 88
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/MinPriorityFeePerGasTransactionSelector.java
  4. 29
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  5. 46
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java
  6. 99
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/MinPriorityFeePerGasTransactionSelectorTest.java
  7. 2
      plugin-api/build.gradle
  8. 9
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java

@ -12,6 +12,8 @@
- Accept `input` and `data` field for the payload of transaction-related RPC methods [#6094](https://github.com/hyperledger/besu/pull/6094)
- Add APIs to set and get the min gas price a transaction must pay for being selected during block creation [#6097](https://github.com/hyperledger/besu/pull/6097)
- TraceService: return results for transactions in block [#6086](https://github.com/hyperledger/besu/pull/6086)
- New option `--min-priority-fee` that sets the minimum priority fee a transaction must meet to be selected for a block. [#6080](https://github.com/hyperledger/besu/pull/6080) [#6083](https://github.com/hyperledger/besu/pull/6083)
- Implement new `miner_setMinPriorityFee` and `miner_getMinPriorityFee` RPC methods [#6080](https://github.com/hyperledger/besu/pull/6080)
### Bug fixes

@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.Abstrac
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AllAcceptingTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlobPriceTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlockSizeTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector;
import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -132,6 +133,7 @@ public class BlockTransactionSelector {
new BlockSizeTransactionSelector(context),
new PriceTransactionSelector(context),
new BlobPriceTransactionSelector(context),
new MinPriorityFeePerGasTransactionSelector(context),
new ProcessingResultTransactionSelector(context));
}

@ -0,0 +1,88 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
/** This class is responsible for selecting transactions based on the minimum priority fee. */
public class MinPriorityFeePerGasTransactionSelector extends AbstractTransactionSelector {
/**
* Constructor for MinPriorityFeeSelector.
*
* @param context The context of block selection.
*/
public MinPriorityFeePerGasTransactionSelector(final BlockSelectionContext context) {
super(context);
}
/**
* Evaluates a transaction before processing.
*
* @param pendingTransaction The transaction to be evaluated.
* @param transactionSelectionResults The results of other transaction evaluations in the same
* block.
* @return TransactionSelectionResult. If the priority fee is below the minimum, it returns an
* invalid transient result. Otherwise, it returns a selected result.
*/
@Override
public TransactionSelectionResult evaluateTransactionPreProcessing(
final PendingTransaction pendingTransaction,
final TransactionSelectionResults transactionSelectionResults) {
if (isPriorityFeePriceBelowMinimum(pendingTransaction)) {
return TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN;
}
return TransactionSelectionResult.SELECTED;
}
/**
* Checks if the priority fee price is below the minimum.
*
* @param pendingTransaction The transaction to check.
* @return boolean. Returns true if the minimum priority fee price is below the minimum, false
* otherwise.
*/
private boolean isPriorityFeePriceBelowMinimum(final PendingTransaction pendingTransaction) {
// Priority txs are exempt from this check
if (pendingTransaction.hasPriority()) {
return false;
}
Wei priorityFeePerGas =
pendingTransaction
.getTransaction()
.getEffectivePriorityFeePerGas(context.processableBlockHeader().getBaseFee());
return priorityFeePerGas.lessThan(context.miningParameters().getMinPriorityFeePerGas());
}
/**
* No evaluation is performed post-processing.
*
* @param pendingTransaction The processed transaction.
* @param processingResult The result of the transaction processing.
* @return Always returns SELECTED.
*/
@Override
public TransactionSelectionResult evaluateTransactionPostProcessing(
final PendingTransaction pendingTransaction,
final TransactionSelectionResults blockTransactionResults,
final TransactionProcessingResult processingResult) {
return TransactionSelectionResult.SELECTED;
}
}

@ -823,6 +823,35 @@ public abstract class AbstractBlockTransactionSelectorTest {
assertThat(results2.getNotSelectedTransactions()).isEmpty();
}
@Test
public void shouldNotSelectTransactionsWithPriorityFeeLessThanConfig() {
ProcessableBlockHeader blockHeader = createBlock(5_000_000, Wei.ONE);
miningParameters.setMinPriorityFeePerGas(Wei.of(7));
final Transaction txSelected = createTransaction(1, Wei.of(8), 100_000);
ensureTransactionIsValid(txSelected);
// transaction txNotSelected should not be selected
final Transaction txNotSelected = createTransaction(2, Wei.of(7), 100_000);
ensureTransactionIsValid(txNotSelected);
transactionPool.addRemoteTransactions(List.of(txSelected, txNotSelected));
final BlockTransactionSelector selector =
createBlockSelector(
transactionProcessor,
blockHeader,
Wei.ZERO,
AddressHelpers.ofValue(1),
Wei.ZERO,
MIN_OCCUPANCY_100_PERCENT);
final TransactionSelectionResults results = selector.buildTransactionListForBlock();
assertThat(results.getSelectedTransactions()).containsOnly(txSelected);
assertThat(results.getNotSelectedTransactions())
.containsOnly(
entry(
txNotSelected, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
}
protected BlockTransactionSelector createBlockSelector(
final MainnetTransactionProcessor transactionProcessor,
final ProcessableBlockHeader blockHeader,

@ -215,4 +215,50 @@ public class LondonFeeMarketBlockTransactionSelectorTest
.containsExactly(txFrontier1, txLondon1, txFrontier2, txLondon2);
assertThat(results.getNotSelectedTransactions()).isEmpty();
}
@Test
@Override
public void shouldNotSelectTransactionsWithPriorityFeeLessThanConfig() {
ProcessableBlockHeader blockHeader = createBlock(5_000_000, Wei.ONE);
miningParameters.setMinPriorityFeePerGas(Wei.of(7));
final Transaction txSelected1 = createEIP1559Transaction(1, Wei.of(8), Wei.of(8), 100_000);
ensureTransactionIsValid(txSelected1);
// transaction txNotSelected1 should not be selected
final Transaction txNotSelected1 = createEIP1559Transaction(2, Wei.of(7), Wei.of(7), 100_000);
ensureTransactionIsValid(txNotSelected1);
// transaction txSelected2 should be selected
final Transaction txSelected2 = createEIP1559Transaction(3, Wei.of(8), Wei.of(8), 100_000);
ensureTransactionIsValid(txSelected2);
// transaction txNotSelected2 should not be selected
final Transaction txNotSelected2 = createEIP1559Transaction(4, Wei.of(8), Wei.of(6), 100_000);
ensureTransactionIsValid(txNotSelected2);
transactionPool.addRemoteTransactions(
List.of(txSelected1, txNotSelected1, txSelected2, txNotSelected2));
assertThat(transactionPool.getPendingTransactions().size()).isEqualTo(4);
final BlockTransactionSelector selector =
createBlockSelector(
transactionProcessor,
blockHeader,
Wei.ZERO,
AddressHelpers.ofValue(1),
Wei.ZERO,
MIN_OCCUPANCY_100_PERCENT);
final TransactionSelectionResults results = selector.buildTransactionListForBlock();
assertThat(results.getSelectedTransactions()).containsOnly(txSelected1, txSelected2);
assertThat(results.getNotSelectedTransactions())
.containsOnly(
entry(
txNotSelected1, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN),
entry(
txNotSelected2, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
}
}

@ -0,0 +1,99 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.blockcreation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AbstractTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class MinPriorityFeePerGasTransactionSelectorTest {
private AbstractTransactionSelector transactionSelector;
private final int minPriorityFeeParameter = 7;
@BeforeEach
public void initialize() {
MiningParameters miningParameters =
MiningParameters.newDefault().setMinPriorityFeePerGas(Wei.of(minPriorityFeeParameter));
BlockSelectionContext context =
new BlockSelectionContext(
miningParameters,
null,
null,
mock(ProcessableBlockHeader.class),
null,
null,
null,
null);
transactionSelector = new MinPriorityFeePerGasTransactionSelector(context);
}
@Test
public void shouldNotSelectWhen_PriorityFeePerGas_IsLessThan_MinPriorityFeePerGas() {
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter - 1);
assertSelectionResult(
transaction, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN);
}
@Test
public void shouldSelectWhen_PriorityFeePerGas_IsEqual_MinPriorityFeePerGas() {
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter);
assertSelectionResult(transaction, TransactionSelectionResult.SELECTED);
}
@Test
public void shouldSelectWhen_PriorityFeePerGas_IsGreaterThan_MinPriorityFeePerGas() {
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter + 1);
assertSelectionResult(transaction, TransactionSelectionResult.SELECTED);
}
@Test
public void shouldSelectWhenPrioritySender() {
var prioritySenderTransaction = mockTransactionWithPriorityFee(minPriorityFeeParameter - 1);
assertSelectionResult(
prioritySenderTransaction,
TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN);
when(prioritySenderTransaction.hasPriority()).thenReturn(true);
assertSelectionResult(prioritySenderTransaction, TransactionSelectionResult.SELECTED);
}
private void assertSelectionResult(
final PendingTransaction transaction, final TransactionSelectionResult expectedResult) {
var actualResult = transactionSelector.evaluateTransactionPreProcessing(transaction, null);
assertThat(actualResult).isEqualTo(expectedResult);
}
private PendingTransaction mockTransactionWithPriorityFee(final int priorityFeePerGas) {
PendingTransaction mockTransaction = mock(PendingTransaction.class);
Transaction transaction = mock(Transaction.class);
when(mockTransaction.getTransaction()).thenReturn(transaction);
when(transaction.getEffectivePriorityFeePerGas(any())).thenReturn(Wei.of(priorityFeePerGas));
return mockTransaction;
}
}

@ -69,7 +69,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = 'ZXBvp7wuHQ8j4Gty2zg/gKdzgrOXSpehYukMuH98W/Y='
knownHash = 'kyCYfllc1IcisRZIYuLxhC+0+POCzcMQPhE8F8mx1Ns='
}
check.dependsOn('checkAPIChanges')

@ -75,12 +75,19 @@ public class TransactionSelectionResult {
public static final TransactionSelectionResult CURRENT_TX_PRICE_BELOW_MIN =
TransactionSelectionResult.invalidTransient("CURRENT_TX_PRICE_BELOW_MIN");
/**
* The transaction has not been selected since its data price is below the current network data
* The transaction has not been selected since its blob price is below the current network blob
* price, but the selection should continue.
*/
public static final TransactionSelectionResult BLOB_PRICE_BELOW_CURRENT_MIN =
TransactionSelectionResult.invalidTransient("BLOB_PRICE_BELOW_CURRENT_MIN");
/**
* The transaction has not been selected since its priority fee is below the configured min
* priority fee per gas, but the selection should continue.
*/
public static final TransactionSelectionResult PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN =
TransactionSelectionResult.invalidTransient("PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN");
private final Status status;
private final Optional<String> maybeInvalidReason;

Loading…
Cancel
Save