Skip to content

Commit 41b9575

Browse files
Add transaction selector based on min priority fee parameter (#6083)
Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
1 parent 236779d commit 41b9575

File tree

8 files changed

+275
-2
lines changed

8 files changed

+275
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
- Accept `input` and `data` field for the payload of transaction-related RPC methods [#6094](https://github.com/hyperledger/besu/pull/6094)
1313
- 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)
1414
- TraceService: return results for transactions in block [#6086](https://github.com/hyperledger/besu/pull/6086)
15+
- 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)
16+
- Implement new `miner_setMinPriorityFee` and `miner_getMinPriorityFee` RPC methods [#6080](https://github.com/hyperledger/besu/pull/6080)
1517

1618
### Bug fixes
1719

ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AllAcceptingTransactionSelector;
2222
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlobPriceTransactionSelector;
2323
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlockSizeTransactionSelector;
24+
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
2425
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector;
2526
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector;
2627
import org.hyperledger.besu.ethereum.chain.Blockchain;
@@ -132,6 +133,7 @@ private List<AbstractTransactionSelector> createTransactionSelectors(
132133
new BlockSizeTransactionSelector(context),
133134
new PriceTransactionSelector(context),
134135
new BlobPriceTransactionSelector(context),
136+
new MinPriorityFeePerGasTransactionSelector(context),
135137
new ProcessingResultTransactionSelector(context));
136138
}
137139

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright Hyperledger Besu Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors;
16+
17+
import org.hyperledger.besu.datatypes.Wei;
18+
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
19+
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
20+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
21+
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
22+
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
23+
24+
/** This class is responsible for selecting transactions based on the minimum priority fee. */
25+
public class MinPriorityFeePerGasTransactionSelector extends AbstractTransactionSelector {
26+
27+
/**
28+
* Constructor for MinPriorityFeeSelector.
29+
*
30+
* @param context The context of block selection.
31+
*/
32+
public MinPriorityFeePerGasTransactionSelector(final BlockSelectionContext context) {
33+
super(context);
34+
}
35+
36+
/**
37+
* Evaluates a transaction before processing.
38+
*
39+
* @param pendingTransaction The transaction to be evaluated.
40+
* @param transactionSelectionResults The results of other transaction evaluations in the same
41+
* block.
42+
* @return TransactionSelectionResult. If the priority fee is below the minimum, it returns an
43+
* invalid transient result. Otherwise, it returns a selected result.
44+
*/
45+
@Override
46+
public TransactionSelectionResult evaluateTransactionPreProcessing(
47+
final PendingTransaction pendingTransaction,
48+
final TransactionSelectionResults transactionSelectionResults) {
49+
if (isPriorityFeePriceBelowMinimum(pendingTransaction)) {
50+
return TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN;
51+
}
52+
return TransactionSelectionResult.SELECTED;
53+
}
54+
55+
/**
56+
* Checks if the priority fee price is below the minimum.
57+
*
58+
* @param pendingTransaction The transaction to check.
59+
* @return boolean. Returns true if the minimum priority fee price is below the minimum, false
60+
* otherwise.
61+
*/
62+
private boolean isPriorityFeePriceBelowMinimum(final PendingTransaction pendingTransaction) {
63+
// Priority txs are exempt from this check
64+
if (pendingTransaction.hasPriority()) {
65+
return false;
66+
}
67+
Wei priorityFeePerGas =
68+
pendingTransaction
69+
.getTransaction()
70+
.getEffectivePriorityFeePerGas(context.processableBlockHeader().getBaseFee());
71+
return priorityFeePerGas.lessThan(context.miningParameters().getMinPriorityFeePerGas());
72+
}
73+
74+
/**
75+
* No evaluation is performed post-processing.
76+
*
77+
* @param pendingTransaction The processed transaction.
78+
* @param processingResult The result of the transaction processing.
79+
* @return Always returns SELECTED.
80+
*/
81+
@Override
82+
public TransactionSelectionResult evaluateTransactionPostProcessing(
83+
final PendingTransaction pendingTransaction,
84+
final TransactionSelectionResults blockTransactionResults,
85+
final TransactionProcessingResult processingResult) {
86+
return TransactionSelectionResult.SELECTED;
87+
}
88+
}

ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,35 @@ public void decreaseOfMinGasPriceAtRuntimeIncludeTxThatWasPreviouslyNotSelected(
823823
assertThat(results2.getNotSelectedTransactions()).isEmpty();
824824
}
825825

826+
@Test
827+
public void shouldNotSelectTransactionsWithPriorityFeeLessThanConfig() {
828+
ProcessableBlockHeader blockHeader = createBlock(5_000_000, Wei.ONE);
829+
miningParameters.setMinPriorityFeePerGas(Wei.of(7));
830+
final Transaction txSelected = createTransaction(1, Wei.of(8), 100_000);
831+
ensureTransactionIsValid(txSelected);
832+
// transaction txNotSelected should not be selected
833+
final Transaction txNotSelected = createTransaction(2, Wei.of(7), 100_000);
834+
ensureTransactionIsValid(txNotSelected);
835+
transactionPool.addRemoteTransactions(List.of(txSelected, txNotSelected));
836+
837+
final BlockTransactionSelector selector =
838+
createBlockSelector(
839+
transactionProcessor,
840+
blockHeader,
841+
Wei.ZERO,
842+
AddressHelpers.ofValue(1),
843+
Wei.ZERO,
844+
MIN_OCCUPANCY_100_PERCENT);
845+
846+
final TransactionSelectionResults results = selector.buildTransactionListForBlock();
847+
848+
assertThat(results.getSelectedTransactions()).containsOnly(txSelected);
849+
assertThat(results.getNotSelectedTransactions())
850+
.containsOnly(
851+
entry(
852+
txNotSelected, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
853+
}
854+
826855
protected BlockTransactionSelector createBlockSelector(
827856
final MainnetTransactionProcessor transactionProcessor,
828857
final ProcessableBlockHeader blockHeader,

ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,50 @@ public void transactionFromSameSenderWithMixedTypes() {
215215
.containsExactly(txFrontier1, txLondon1, txFrontier2, txLondon2);
216216
assertThat(results.getNotSelectedTransactions()).isEmpty();
217217
}
218+
219+
@Test
220+
@Override
221+
public void shouldNotSelectTransactionsWithPriorityFeeLessThanConfig() {
222+
ProcessableBlockHeader blockHeader = createBlock(5_000_000, Wei.ONE);
223+
miningParameters.setMinPriorityFeePerGas(Wei.of(7));
224+
225+
final Transaction txSelected1 = createEIP1559Transaction(1, Wei.of(8), Wei.of(8), 100_000);
226+
ensureTransactionIsValid(txSelected1);
227+
228+
// transaction txNotSelected1 should not be selected
229+
final Transaction txNotSelected1 = createEIP1559Transaction(2, Wei.of(7), Wei.of(7), 100_000);
230+
ensureTransactionIsValid(txNotSelected1);
231+
232+
// transaction txSelected2 should be selected
233+
final Transaction txSelected2 = createEIP1559Transaction(3, Wei.of(8), Wei.of(8), 100_000);
234+
ensureTransactionIsValid(txSelected2);
235+
236+
// transaction txNotSelected2 should not be selected
237+
final Transaction txNotSelected2 = createEIP1559Transaction(4, Wei.of(8), Wei.of(6), 100_000);
238+
ensureTransactionIsValid(txNotSelected2);
239+
240+
transactionPool.addRemoteTransactions(
241+
List.of(txSelected1, txNotSelected1, txSelected2, txNotSelected2));
242+
243+
assertThat(transactionPool.getPendingTransactions().size()).isEqualTo(4);
244+
245+
final BlockTransactionSelector selector =
246+
createBlockSelector(
247+
transactionProcessor,
248+
blockHeader,
249+
Wei.ZERO,
250+
AddressHelpers.ofValue(1),
251+
Wei.ZERO,
252+
MIN_OCCUPANCY_100_PERCENT);
253+
254+
final TransactionSelectionResults results = selector.buildTransactionListForBlock();
255+
256+
assertThat(results.getSelectedTransactions()).containsOnly(txSelected1, txSelected2);
257+
assertThat(results.getNotSelectedTransactions())
258+
.containsOnly(
259+
entry(
260+
txNotSelected1, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN),
261+
entry(
262+
txNotSelected2, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
263+
}
218264
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright Hyperledger Besu Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.blockcreation;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.mockito.ArgumentMatchers.any;
19+
import static org.mockito.Mockito.mock;
20+
import static org.mockito.Mockito.when;
21+
22+
import org.hyperledger.besu.datatypes.Wei;
23+
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
24+
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AbstractTransactionSelector;
25+
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
26+
import org.hyperledger.besu.ethereum.core.MiningParameters;
27+
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
28+
import org.hyperledger.besu.ethereum.core.Transaction;
29+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
30+
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
31+
32+
import org.junit.jupiter.api.BeforeEach;
33+
import org.junit.jupiter.api.Test;
34+
35+
public class MinPriorityFeePerGasTransactionSelectorTest {
36+
private AbstractTransactionSelector transactionSelector;
37+
38+
private final int minPriorityFeeParameter = 7;
39+
40+
@BeforeEach
41+
public void initialize() {
42+
MiningParameters miningParameters =
43+
MiningParameters.newDefault().setMinPriorityFeePerGas(Wei.of(minPriorityFeeParameter));
44+
BlockSelectionContext context =
45+
new BlockSelectionContext(
46+
miningParameters,
47+
null,
48+
null,
49+
mock(ProcessableBlockHeader.class),
50+
null,
51+
null,
52+
null,
53+
null);
54+
transactionSelector = new MinPriorityFeePerGasTransactionSelector(context);
55+
}
56+
57+
@Test
58+
public void shouldNotSelectWhen_PriorityFeePerGas_IsLessThan_MinPriorityFeePerGas() {
59+
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter - 1);
60+
assertSelectionResult(
61+
transaction, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN);
62+
}
63+
64+
@Test
65+
public void shouldSelectWhen_PriorityFeePerGas_IsEqual_MinPriorityFeePerGas() {
66+
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter);
67+
assertSelectionResult(transaction, TransactionSelectionResult.SELECTED);
68+
}
69+
70+
@Test
71+
public void shouldSelectWhen_PriorityFeePerGas_IsGreaterThan_MinPriorityFeePerGas() {
72+
var transaction = mockTransactionWithPriorityFee(minPriorityFeeParameter + 1);
73+
assertSelectionResult(transaction, TransactionSelectionResult.SELECTED);
74+
}
75+
76+
@Test
77+
public void shouldSelectWhenPrioritySender() {
78+
var prioritySenderTransaction = mockTransactionWithPriorityFee(minPriorityFeeParameter - 1);
79+
assertSelectionResult(
80+
prioritySenderTransaction,
81+
TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN);
82+
when(prioritySenderTransaction.hasPriority()).thenReturn(true);
83+
assertSelectionResult(prioritySenderTransaction, TransactionSelectionResult.SELECTED);
84+
}
85+
86+
private void assertSelectionResult(
87+
final PendingTransaction transaction, final TransactionSelectionResult expectedResult) {
88+
var actualResult = transactionSelector.evaluateTransactionPreProcessing(transaction, null);
89+
assertThat(actualResult).isEqualTo(expectedResult);
90+
}
91+
92+
private PendingTransaction mockTransactionWithPriorityFee(final int priorityFeePerGas) {
93+
PendingTransaction mockTransaction = mock(PendingTransaction.class);
94+
Transaction transaction = mock(Transaction.class);
95+
when(mockTransaction.getTransaction()).thenReturn(transaction);
96+
when(transaction.getEffectivePriorityFeePerGas(any())).thenReturn(Wei.of(priorityFeePerGas));
97+
return mockTransaction;
98+
}
99+
}

plugin-api/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Calculated : ${currentHash}
6969
tasks.register('checkAPIChanges', FileStateChecker) {
7070
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
7171
files = sourceSets.main.allJava.files
72-
knownHash = 'ZXBvp7wuHQ8j4Gty2zg/gKdzgrOXSpehYukMuH98W/Y='
72+
knownHash = 'kyCYfllc1IcisRZIYuLxhC+0+POCzcMQPhE8F8mx1Ns='
7373
}
7474
check.dependsOn('checkAPIChanges')
7575

plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,19 @@ public String toString() {
7575
public static final TransactionSelectionResult CURRENT_TX_PRICE_BELOW_MIN =
7676
TransactionSelectionResult.invalidTransient("CURRENT_TX_PRICE_BELOW_MIN");
7777
/**
78-
* The transaction has not been selected since its data price is below the current network data
78+
* The transaction has not been selected since its blob price is below the current network blob
7979
* price, but the selection should continue.
8080
*/
8181
public static final TransactionSelectionResult BLOB_PRICE_BELOW_CURRENT_MIN =
8282
TransactionSelectionResult.invalidTransient("BLOB_PRICE_BELOW_CURRENT_MIN");
8383

84+
/**
85+
* The transaction has not been selected since its priority fee is below the configured min
86+
* priority fee per gas, but the selection should continue.
87+
*/
88+
public static final TransactionSelectionResult PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN =
89+
TransactionSelectionResult.invalidTransient("PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN");
90+
8491
private final Status status;
8592
private final Optional<String> maybeInvalidReason;
8693

0 commit comments

Comments
 (0)