mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 07:18:06 -05:00
Allow a transaction selection plugin to specify custom selection results (#6190)
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- Implement debug_traceCall [#5885](https://github.com/hyperledger/besu/pull/5885)
|
||||
- Transactions that takes too long to evaluate, during block creation, are dropped from the txpool [#6163](https://github.com/hyperledger/besu/pull/6163)
|
||||
- New option `tx-pool-min-gas-price` to set a lower bound when accepting txs to the pool [#6098](https://github.com/hyperledger/besu/pull/6098)
|
||||
- Allow a transaction selection plugin to specify custom selection results [#6190](https://github.com/hyperledger/besu/pull/6190)
|
||||
|
||||
## 23.10.2
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -227,11 +228,11 @@ public class BlockTransactionSelector {
|
||||
final PendingTransaction pendingTransaction) {
|
||||
checkCancellation();
|
||||
|
||||
final long evaluationStartedAt = System.currentTimeMillis();
|
||||
final Stopwatch evaluationTimer = Stopwatch.createStarted();
|
||||
|
||||
TransactionSelectionResult selectionResult = evaluatePreProcessing(pendingTransaction);
|
||||
if (!selectionResult.selected()) {
|
||||
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationStartedAt);
|
||||
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationTimer);
|
||||
}
|
||||
|
||||
final WorldUpdater txWorldStateUpdater = blockWorldStateUpdater.updater();
|
||||
@@ -243,13 +244,10 @@ public class BlockTransactionSelector {
|
||||
|
||||
if (postProcessingSelectionResult.selected()) {
|
||||
return handleTransactionSelected(
|
||||
pendingTransaction, processingResult, txWorldStateUpdater, evaluationStartedAt);
|
||||
pendingTransaction, processingResult, txWorldStateUpdater, evaluationTimer);
|
||||
}
|
||||
return handleTransactionNotSelected(
|
||||
pendingTransaction,
|
||||
postProcessingSelectionResult,
|
||||
txWorldStateUpdater,
|
||||
evaluationStartedAt);
|
||||
pendingTransaction, postProcessingSelectionResult, txWorldStateUpdater, evaluationTimer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,14 +331,14 @@ public class BlockTransactionSelector {
|
||||
* @param pendingTransaction The pending transaction.
|
||||
* @param processingResult The result of the transaction processing.
|
||||
* @param txWorldStateUpdater The world state updater.
|
||||
* @param evaluationStartedAt when the evaluation of this tx started
|
||||
* @param evaluationTimer tracks the evaluation elapsed time
|
||||
* @return The result of the transaction selection process.
|
||||
*/
|
||||
private TransactionSelectionResult handleTransactionSelected(
|
||||
final PendingTransaction pendingTransaction,
|
||||
final TransactionProcessingResult processingResult,
|
||||
final WorldUpdater txWorldStateUpdater,
|
||||
final long evaluationStartedAt) {
|
||||
final Stopwatch evaluationTimer) {
|
||||
final Transaction transaction = pendingTransaction.getTransaction();
|
||||
|
||||
final long gasUsedByTransaction =
|
||||
@@ -369,20 +367,19 @@ public class BlockTransactionSelector {
|
||||
}
|
||||
}
|
||||
|
||||
final long evaluationTime = System.currentTimeMillis() - evaluationStartedAt;
|
||||
if (tooLate) {
|
||||
// even if this tx passed all the checks, it is too late to include it in this block,
|
||||
// so we need to treat it as not selected
|
||||
|
||||
// check if this tx took too much to evaluate, and in case remove it from the pool
|
||||
final TransactionSelectionResult timeoutSelectionResult;
|
||||
if (evaluationTime > blockTxsSelectionMaxTime) {
|
||||
if (evaluationTimer.elapsed(TimeUnit.MILLISECONDS) > blockTxsSelectionMaxTime) {
|
||||
LOG.atWarn()
|
||||
.setMessage(
|
||||
"Transaction {} is too late for inclusion, evaluated in {}ms that is over the max limit of {}"
|
||||
"Transaction {} is too late for inclusion, evaluated in {} that is over the max limit of {}ms"
|
||||
+ ", removing it from the pool")
|
||||
.addArgument(transaction::toTraceLog)
|
||||
.addArgument(evaluationTime)
|
||||
.addArgument(evaluationTimer)
|
||||
.addArgument(blockTxsSelectionMaxTime)
|
||||
.log();
|
||||
timeoutSelectionResult = TX_EVALUATION_TOO_LONG;
|
||||
@@ -390,7 +387,7 @@ public class BlockTransactionSelector {
|
||||
LOG.atTrace()
|
||||
.setMessage("Transaction {} is too late for inclusion")
|
||||
.addArgument(transaction::toTraceLog)
|
||||
.addArgument(evaluationTime)
|
||||
.addArgument(evaluationTimer)
|
||||
.log();
|
||||
timeoutSelectionResult = BLOCK_SELECTION_TIMEOUT;
|
||||
}
|
||||
@@ -398,15 +395,15 @@ public class BlockTransactionSelector {
|
||||
// do not rely on the presence of this result, since by the time it is added, the code
|
||||
// reading it could have been already executed by another thread
|
||||
return handleTransactionNotSelected(
|
||||
pendingTransaction, timeoutSelectionResult, txWorldStateUpdater, evaluationStartedAt);
|
||||
pendingTransaction, timeoutSelectionResult, txWorldStateUpdater, evaluationTimer);
|
||||
}
|
||||
|
||||
pluginTransactionSelector.onTransactionSelected(pendingTransaction, processingResult);
|
||||
blockWorldStateUpdater = worldState.updater();
|
||||
LOG.atTrace()
|
||||
.setMessage("Selected {} for block creation, evaluated in {}ms")
|
||||
.setMessage("Selected {} for block creation, evaluated in {}")
|
||||
.addArgument(transaction::toTraceLog)
|
||||
.addArgument(evaluationTime)
|
||||
.addArgument(evaluationTimer)
|
||||
.log();
|
||||
return SELECTED;
|
||||
}
|
||||
@@ -418,22 +415,22 @@ public class BlockTransactionSelector {
|
||||
*
|
||||
* @param pendingTransaction The unselected pending transaction.
|
||||
* @param selectionResult The result of the transaction selection process.
|
||||
* @param evaluationStartedAt when the evaluation of this tx started
|
||||
* @param evaluationTimer tracks the evaluation elapsed time
|
||||
* @return The result of the transaction selection process.
|
||||
*/
|
||||
private TransactionSelectionResult handleTransactionNotSelected(
|
||||
final PendingTransaction pendingTransaction,
|
||||
final TransactionSelectionResult selectionResult,
|
||||
final long evaluationStartedAt) {
|
||||
final Stopwatch evaluationTimer) {
|
||||
|
||||
transactionSelectionResults.updateNotSelected(
|
||||
pendingTransaction.getTransaction(), selectionResult);
|
||||
pluginTransactionSelector.onTransactionNotSelected(pendingTransaction, selectionResult);
|
||||
LOG.atTrace()
|
||||
.setMessage("Not selected {} for block creation with result {}, evaluated in {}ms")
|
||||
.setMessage("Not selected {} for block creation with result {}, evaluated in {}")
|
||||
.addArgument(pendingTransaction::toTraceLog)
|
||||
.addArgument(selectionResult)
|
||||
.addArgument(() -> System.currentTimeMillis() - evaluationStartedAt)
|
||||
.addArgument(evaluationTimer)
|
||||
.log();
|
||||
|
||||
return selectionResult;
|
||||
@@ -443,9 +440,9 @@ public class BlockTransactionSelector {
|
||||
final PendingTransaction pendingTransaction,
|
||||
final TransactionSelectionResult selectionResult,
|
||||
final WorldUpdater txWorldStateUpdater,
|
||||
final long evaluationStartedAt) {
|
||||
final Stopwatch evaluationTimer) {
|
||||
txWorldStateUpdater.revert();
|
||||
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationStartedAt);
|
||||
return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationTimer);
|
||||
}
|
||||
|
||||
private void checkCancellation() {
|
||||
|
||||
@@ -111,7 +111,7 @@ public class TransactionSelectionResults {
|
||||
"Selection stats: Totals[Evaluated={}, Selected={}, NotSelected={}, Discarded={}]; Detailed[{}]",
|
||||
selectedTransactions.size() + notSelectedTxs.size(),
|
||||
selectedTransactions.size(),
|
||||
notSelectedStats.size(),
|
||||
notSelectedTxs.size(),
|
||||
notSelectedStats.entrySet().stream()
|
||||
.filter(e -> e.getKey().discard())
|
||||
.map(Map.Entry::getValue)
|
||||
|
||||
@@ -89,8 +89,9 @@ public class PriceTransactionSelector extends AbstractTransactionSelector {
|
||||
.setMessage(
|
||||
"Current gas price of {} is {} and lower than the configured minimum {}, skipping")
|
||||
.addArgument(pendingTransaction::toTraceLog)
|
||||
.addArgument(transactionGasPriceInBlock)
|
||||
.addArgument(context.miningParameters()::getMinTransactionGasPrice)
|
||||
.addArgument(transactionGasPriceInBlock::toHumanReadableString)
|
||||
.addArgument(
|
||||
context.miningParameters().getMinTransactionGasPrice()::toHumanReadableString)
|
||||
.log();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -583,9 +583,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
final PendingTransaction pendingTransaction) {
|
||||
if (pendingTransaction.getTransaction().equals(notSelectedTransient))
|
||||
return TransactionSelectionResult.invalidTransient("transient");
|
||||
return PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT;
|
||||
if (pendingTransaction.getTransaction().equals(notSelectedInvalid))
|
||||
return TransactionSelectionResult.invalid("invalid");
|
||||
return PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID;
|
||||
return SELECTED;
|
||||
}
|
||||
|
||||
@@ -618,8 +618,10 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
assertThat(transactionSelectionResults.getSelectedTransactions()).containsOnly(selected);
|
||||
assertThat(transactionSelectionResults.getNotSelectedTransactions())
|
||||
.containsOnly(
|
||||
entry(notSelectedTransient, TransactionSelectionResult.invalidTransient("transient")),
|
||||
entry(notSelectedInvalid, TransactionSelectionResult.invalid("invalid")));
|
||||
entry(
|
||||
notSelectedTransient,
|
||||
PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT),
|
||||
entry(notSelectedInvalid, PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -654,7 +656,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
processingResult) {
|
||||
// the transaction with max gas +1 should fail
|
||||
if (processingResult.getEstimateGasUsedByTransaction() > maxGasUsedByTransaction) {
|
||||
return TransactionSelectionResult.invalidTransient("Invalid");
|
||||
return PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT;
|
||||
}
|
||||
return SELECTED;
|
||||
}
|
||||
@@ -678,7 +680,8 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
|
||||
assertThat(transactionSelectionResults.getSelectedTransactions()).contains(selected, selected3);
|
||||
assertThat(transactionSelectionResults.getNotSelectedTransactions())
|
||||
.containsOnly(entry(notSelected, TransactionSelectionResult.invalidTransient("Invalid")));
|
||||
.containsOnly(
|
||||
entry(notSelected, PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1189,4 +1192,48 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static class PluginTransactionSelectionResult extends TransactionSelectionResult {
|
||||
private enum PluginStatus implements Status {
|
||||
PLUGIN_INVALID(false, true),
|
||||
PLUGIN_INVALID_TRANSIENT(false, false);
|
||||
|
||||
private final boolean stop;
|
||||
private final boolean discard;
|
||||
|
||||
PluginStatus(final boolean stop, final boolean discard) {
|
||||
this.stop = stop;
|
||||
this.discard = discard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
return stop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean discard() {
|
||||
return discard;
|
||||
}
|
||||
}
|
||||
|
||||
public static final TransactionSelectionResult GENERIC_PLUGIN_INVALID_TRANSIENT =
|
||||
invalidTransient("GENERIC_PLUGIN_INVALID_TRANSIENT");
|
||||
|
||||
public static final TransactionSelectionResult GENERIC_PLUGIN_INVALID =
|
||||
invalid("GENERIC_PLUGIN_INVALID");
|
||||
|
||||
private PluginTransactionSelectionResult(final Status status, final String invalidReason) {
|
||||
super(status, invalidReason);
|
||||
}
|
||||
|
||||
public static TransactionSelectionResult invalidTransient(final String invalidReason) {
|
||||
return new PluginTransactionSelectionResult(
|
||||
PluginStatus.PLUGIN_INVALID_TRANSIENT, invalidReason);
|
||||
}
|
||||
|
||||
public static TransactionSelectionResult invalid(final String invalidReason) {
|
||||
return new PluginTransactionSelectionResult(PluginStatus.PLUGIN_INVALID, invalidReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = 'gKRXd2Ow7wYKSgeGrDMRj0+2LdCzjOhLx8UEno9btGw='
|
||||
knownHash = 'nB1LhUpMWYFQpBdNJ/3Q79c8kLgUgPmEFzlRMlLUl1Y='
|
||||
}
|
||||
check.dependsOn('checkAPIChanges')
|
||||
|
||||
|
||||
@@ -24,7 +24,34 @@ import java.util.Optional;
|
||||
*/
|
||||
public class TransactionSelectionResult {
|
||||
|
||||
private enum Status {
|
||||
/**
|
||||
* Represent the status of a transaction selection result. Plugin can extend this to implement its
|
||||
* own statuses.
|
||||
*/
|
||||
protected interface Status {
|
||||
/**
|
||||
* Should the selection process be stopped?
|
||||
*
|
||||
* @return true if the selection process needs to be stopped
|
||||
*/
|
||||
boolean stop();
|
||||
|
||||
/**
|
||||
* Should the current transaction be removed from the txpool?
|
||||
*
|
||||
* @return yes if the transaction should be removed from the txpool
|
||||
*/
|
||||
boolean discard();
|
||||
|
||||
/**
|
||||
* Name of this status
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String name();
|
||||
}
|
||||
|
||||
private enum BaseStatus implements Status {
|
||||
SELECTED,
|
||||
BLOCK_FULL(true, false),
|
||||
BLOCK_OCCUPANCY_ABOVE_THRESHOLD(true, false),
|
||||
@@ -36,12 +63,12 @@ public class TransactionSelectionResult {
|
||||
private final boolean stop;
|
||||
private final boolean discard;
|
||||
|
||||
Status() {
|
||||
BaseStatus() {
|
||||
this.stop = false;
|
||||
this.discard = false;
|
||||
}
|
||||
|
||||
Status(final boolean stop, final boolean discard) {
|
||||
BaseStatus(final boolean stop, final boolean discard) {
|
||||
this.stop = stop;
|
||||
this.discard = discard;
|
||||
}
|
||||
@@ -50,26 +77,36 @@ public class TransactionSelectionResult {
|
||||
public String toString() {
|
||||
return name() + " (stop=" + stop + ", discard=" + discard + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
return stop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean discard() {
|
||||
return discard;
|
||||
}
|
||||
}
|
||||
|
||||
/** The transaction has been selected to be included in the new block */
|
||||
public static final TransactionSelectionResult SELECTED =
|
||||
new TransactionSelectionResult(Status.SELECTED);
|
||||
new TransactionSelectionResult(BaseStatus.SELECTED);
|
||||
/** The transaction has not been selected since the block is full. */
|
||||
public static final TransactionSelectionResult BLOCK_FULL =
|
||||
new TransactionSelectionResult(Status.BLOCK_FULL);
|
||||
new TransactionSelectionResult(BaseStatus.BLOCK_FULL);
|
||||
/** There was no more time to add transaction to the block */
|
||||
public static final TransactionSelectionResult BLOCK_SELECTION_TIMEOUT =
|
||||
new TransactionSelectionResult(Status.BLOCK_SELECTION_TIMEOUT);
|
||||
new TransactionSelectionResult(BaseStatus.BLOCK_SELECTION_TIMEOUT);
|
||||
/** Transaction took too much to evaluate */
|
||||
public static final TransactionSelectionResult TX_EVALUATION_TOO_LONG =
|
||||
new TransactionSelectionResult(Status.TX_EVALUATION_TOO_LONG);
|
||||
new TransactionSelectionResult(BaseStatus.TX_EVALUATION_TOO_LONG);
|
||||
/**
|
||||
* The transaction has not been selected since too large and the occupancy of the block is enough
|
||||
* to stop the selection.
|
||||
*/
|
||||
public static final TransactionSelectionResult BLOCK_OCCUPANCY_ABOVE_THRESHOLD =
|
||||
new TransactionSelectionResult(Status.BLOCK_OCCUPANCY_ABOVE_THRESHOLD);
|
||||
new TransactionSelectionResult(BaseStatus.BLOCK_OCCUPANCY_ABOVE_THRESHOLD);
|
||||
/**
|
||||
* The transaction has not been selected since its gas limit is greater than the block remaining
|
||||
* gas, but the selection should continue.
|
||||
@@ -99,11 +136,22 @@ public class TransactionSelectionResult {
|
||||
private final Status status;
|
||||
private final Optional<String> maybeInvalidReason;
|
||||
|
||||
private TransactionSelectionResult(final Status status) {
|
||||
/**
|
||||
* Create a new transaction selection result with the passed status
|
||||
*
|
||||
* @param status the selection result status
|
||||
*/
|
||||
protected TransactionSelectionResult(final Status status) {
|
||||
this(status, null);
|
||||
}
|
||||
|
||||
private TransactionSelectionResult(final Status status, final String invalidReason) {
|
||||
/**
|
||||
* Create a new transaction selection result with the passed status and invalid reason
|
||||
*
|
||||
* @param status the selection result status
|
||||
* @param invalidReason string with a custom invalid reason
|
||||
*/
|
||||
protected TransactionSelectionResult(final Status status, final String invalidReason) {
|
||||
this.status = status;
|
||||
this.maybeInvalidReason = Optional.ofNullable(invalidReason);
|
||||
}
|
||||
@@ -116,7 +164,7 @@ public class TransactionSelectionResult {
|
||||
* @return the selection result
|
||||
*/
|
||||
public static TransactionSelectionResult invalidTransient(final String invalidReason) {
|
||||
return new TransactionSelectionResult(Status.INVALID_TRANSIENT, invalidReason);
|
||||
return new TransactionSelectionResult(BaseStatus.INVALID_TRANSIENT, invalidReason);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +175,7 @@ public class TransactionSelectionResult {
|
||||
* @return the selection result
|
||||
*/
|
||||
public static TransactionSelectionResult invalid(final String invalidReason) {
|
||||
return new TransactionSelectionResult(Status.INVALID, invalidReason);
|
||||
return new TransactionSelectionResult(BaseStatus.INVALID, invalidReason);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +184,7 @@ public class TransactionSelectionResult {
|
||||
* @return true if the selection process should stop, false otherwise
|
||||
*/
|
||||
public boolean stop() {
|
||||
return status.stop;
|
||||
return status.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +194,7 @@ public class TransactionSelectionResult {
|
||||
* otherwise
|
||||
*/
|
||||
public boolean discard() {
|
||||
return status.discard;
|
||||
return status.discard();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +203,7 @@ public class TransactionSelectionResult {
|
||||
* @return true if the candidate transaction is included in the new block, false otherwise
|
||||
*/
|
||||
public boolean selected() {
|
||||
return Status.SELECTED.equals(status);
|
||||
return BaseStatus.SELECTED.equals(status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user