diff --git a/CHANGELOG.md b/CHANGELOG.md index e0e64087c04..eea989cc957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,6 @@ # Changelog ## [Unreleased] -- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) - ### Upcoming Breaking Changes - k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release @@ -14,7 +12,8 @@ - Remove privacy test classes support [#7569](https://github.com/hyperledger/besu/pull/7569) - Add Blob Transaction Metrics [#7622](https://github.com/hyperledger/besu/pull/7622) - Implemented support for emptyBlockPeriodSeconds in QBFT [#6965](https://github.com/hyperledger/besu/pull/6965) - +- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) +- Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673) ### Bug fixes - Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java index e07b43b9904..5370d2ec46c 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT; +import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT_INVALID_TX; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.INVALID_TX_EVALUATION_TOO_LONG; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG; @@ -52,9 +53,11 @@ import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import java.time.Duration; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -97,11 +100,12 @@ public class BlockTransactionSelector { new TransactionSelectionResults(); private final List transactionSelectors; private final PluginTransactionSelector pluginTransactionSelector; - private final BlockAwareOperationTracer pluginOperationTracer; + private final BlockAwareOperationTracer operationTracer; private final EthScheduler ethScheduler; private final AtomicBoolean isTimeout = new AtomicBoolean(false); private final long blockTxsSelectionMaxTime; private WorldUpdater blockWorldStateUpdater; + private volatile TransactionEvaluationContext currTxEvaluationContext; public BlockTransactionSelector( final MiningParameters miningParameters, @@ -139,7 +143,8 @@ public BlockTransactionSelector( transactionPool); transactionSelectors = createTransactionSelectors(blockSelectionContext); this.pluginTransactionSelector = pluginTransactionSelector; - this.pluginOperationTracer = pluginTransactionSelector.getOperationTracer(); + this.operationTracer = + new InterruptibleOperationTracer(pluginTransactionSelector.getOperationTracer()); blockWorldStateUpdater = worldState.updater(); blockTxsSelectionMaxTime = miningParameters.getBlockTxsSelectionMaxTime(); } @@ -178,15 +183,17 @@ public TransactionSelectionResults buildTransactionListForBlock() { } private void timeLimitedSelection() { - final var txSelection = - ethScheduler.scheduleBlockCreationTask( + final var txSelectionTask = + new FutureTask( () -> blockSelectionContext .transactionPool() - .selectTransactions(this::evaluateTransaction)); + .selectTransactions(this::evaluateTransaction), + null); + ethScheduler.scheduleBlockCreationTask(txSelectionTask); try { - txSelection.get(blockTxsSelectionMaxTime, TimeUnit.MILLISECONDS); + txSelectionTask.get(blockTxsSelectionMaxTime, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException e) { if (isCancelled.get()) { throw new CancellationException("Cancelled during transaction selection"); @@ -197,6 +204,9 @@ private void timeLimitedSelection() { synchronized (isTimeout) { isTimeout.set(true); } + + cancelEvaluatingTxWithGraceTime(txSelectionTask); + LOG.warn( "Interrupting the selection of transactions for block inclusion as it exceeds the maximum configured duration of " + blockTxsSelectionMaxTime @@ -205,6 +215,40 @@ private void timeLimitedSelection() { } } + private void cancelEvaluatingTxWithGraceTime(final FutureTask txSelectionTask) { + final long elapsedTime = + currTxEvaluationContext.getEvaluationTimer().elapsed(TimeUnit.MILLISECONDS); + // adding 100ms so we are sure it take strictly more than the block selection max time + final long txRemainingTime = (blockTxsSelectionMaxTime - elapsedTime) + 100; + + LOG.atDebug() + .setMessage( + "Transaction {} is processing for {}ms, giving it {}ms grace time, before considering it taking too much time to execute") + .addArgument(currTxEvaluationContext.getPendingTransaction()::toTraceLog) + .addArgument(elapsedTime) + .addArgument(txRemainingTime) + .log(); + + ethScheduler.scheduleFutureTask( + () -> { + if (!txSelectionTask.isDone()) { + LOG.atDebug() + .setMessage( + "Transaction {} is still processing after the grace time, total processing time {}ms," + + " greater than max block selection time of {}ms, forcing an interrupt") + .addArgument(currTxEvaluationContext.getPendingTransaction()::toTraceLog) + .addArgument( + () -> + currTxEvaluationContext.getEvaluationTimer().elapsed(TimeUnit.MILLISECONDS)) + .addArgument(blockTxsSelectionMaxTime) + .log(); + + txSelectionTask.cancel(true); + } + }, + Duration.ofMillis(txRemainingTime)); + } + /** * Evaluates a list of transactions and updates the selection results accordingly. If a * transaction is not selected during the evaluation, it is updated as not selected in the @@ -236,6 +280,7 @@ private TransactionSelectionResult evaluateTransaction( final TransactionEvaluationContext evaluationContext = createTransactionEvaluationContext(pendingTransaction); + currTxEvaluationContext = evaluationContext; TransactionSelectionResult selectionResult = evaluatePreProcessing(evaluationContext); if (!selectionResult.selected()) { @@ -337,7 +382,7 @@ private TransactionProcessingResult processTransaction( blockSelectionContext.pendingBlockHeader(), pendingTransaction.getTransaction(), blockSelectionContext.miningBeneficiary(), - pluginOperationTracer, + operationTracer, blockHashLookup, false, TransactionValidationParams.mining(), @@ -422,14 +467,10 @@ private TransactionSelectionResult handleTransactionNotSelected( final var pendingTransaction = evaluationContext.getPendingTransaction(); // check if this tx took too much to evaluate, and in case it was invalid remove it from the - // pool, otherwise penalize it. + // pool, otherwise penalize it. Not synchronized since there is no state change here. final TransactionSelectionResult actualResult = isTimeout.get() - ? transactionTookTooLong(evaluationContext, selectionResult) - ? selectionResult.discard() - ? INVALID_TX_EVALUATION_TOO_LONG - : TX_EVALUATION_TOO_LONG - : BLOCK_SELECTION_TIMEOUT + ? rewriteSelectionResultForTimeout(evaluationContext, selectionResult) : selectionResult; transactionSelectionResults.updateNotSelected(evaluationContext.getTransaction(), actualResult); @@ -446,6 +487,34 @@ private TransactionSelectionResult handleTransactionNotSelected( return actualResult; } + /** + * In case of a block creation timeout, we rewrite the selection result, so we can easily spot + * what happened looking at the transaction selection results. + * + * @param evaluationContext The current selection session data. + * @param selectionResult The result of the transaction selection process. + * @return the rewritten selection result + */ + private TransactionSelectionResult rewriteSelectionResultForTimeout( + final TransactionEvaluationContext evaluationContext, + final TransactionSelectionResult selectionResult) { + + if (transactionTookTooLong(evaluationContext, selectionResult)) { + return selectionResult.discard() ? INVALID_TX_EVALUATION_TOO_LONG : TX_EVALUATION_TOO_LONG; + } + + return selectionResult.discard() ? BLOCK_SELECTION_TIMEOUT_INVALID_TX : BLOCK_SELECTION_TIMEOUT; + } + + /** + * Check if the evaluation of this tx took more than the block creation max time, because if true + * we want to penalize it. We penalize it, instead of directly removing, because it could happen + * that the tx will evaluate in time next time. Invalid txs are always removed. + * + * @param evaluationContext The current selection session data. + * @param selectionResult The result of the transaction selection process. + * @return true if the evaluation of this tx took more than the block creation max time + */ private boolean transactionTookTooLong( final TransactionEvaluationContext evaluationContext, final TransactionSelectionResult selectionResult) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/InterruptibleOperationTracer.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/InterruptibleOperationTracer.java new file mode 100644 index 00000000000..eb7f34bd9a0 --- /dev/null +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/InterruptibleOperationTracer.java @@ -0,0 +1,143 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.log.Log; +import org.hyperledger.besu.evm.operation.Operation; +import org.hyperledger.besu.evm.worldstate.WorldView; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; +import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.tuweni.bytes.Bytes; + +public class InterruptibleOperationTracer implements BlockAwareOperationTracer { + private final BlockAwareOperationTracer delegate; + + public InterruptibleOperationTracer(final BlockAwareOperationTracer delegate) { + this.delegate = delegate; + } + + @Override + public void traceStartBlock(final BlockHeader blockHeader, final BlockBody blockBody) { + delegate.traceStartBlock(blockHeader, blockBody); + } + + @Override + public void traceEndBlock(final BlockHeader blockHeader, final BlockBody blockBody) { + delegate.traceEndBlock(blockHeader, blockBody); + } + + @Override + public void traceStartBlock(final ProcessableBlockHeader processableBlockHeader) { + delegate.traceStartBlock(processableBlockHeader); + } + + @Override + public boolean isExtendedTracing() { + return delegate.isExtendedTracing(); + } + + @Override + public void tracePreExecution(final MessageFrame frame) { + checkInterrupt(); + delegate.tracePreExecution(frame); + } + + @Override + public void tracePostExecution( + final MessageFrame frame, final Operation.OperationResult operationResult) { + checkInterrupt(); + delegate.tracePostExecution(frame, operationResult); + } + + @Override + public void tracePrecompileCall( + final MessageFrame frame, final long gasRequirement, final Bytes output) { + checkInterrupt(); + delegate.tracePrecompileCall(frame, gasRequirement, output); + } + + @Override + public void traceAccountCreationResult( + final MessageFrame frame, final Optional haltReason) { + checkInterrupt(); + delegate.traceAccountCreationResult(frame, haltReason); + } + + @Override + public void tracePrepareTransaction(final WorldView worldView, final Transaction transaction) { + delegate.tracePrepareTransaction(worldView, transaction); + } + + @Override + public void traceStartTransaction(final WorldView worldView, final Transaction transaction) { + delegate.traceStartTransaction(worldView, transaction); + } + + @Override + public void traceBeforeRewardTransaction( + final WorldView worldView, final Transaction tx, final Wei miningReward) { + delegate.traceBeforeRewardTransaction(worldView, tx, miningReward); + } + + @Override + public void traceEndTransaction( + final WorldView worldView, + final Transaction tx, + final boolean status, + final Bytes output, + final List logs, + final long gasUsed, + final Set
selfDestructs, + final long timeNs) { + delegate.traceEndTransaction( + worldView, tx, status, output, logs, gasUsed, selfDestructs, timeNs); + } + + @Override + public void traceContextEnter(final MessageFrame frame) { + checkInterrupt(); + delegate.traceContextEnter(frame); + } + + @Override + public void traceContextReEnter(final MessageFrame frame) { + checkInterrupt(); + delegate.traceContextReEnter(frame); + } + + @Override + public void traceContextExit(final MessageFrame frame) { + checkInterrupt(); + delegate.traceContextExit(frame); + } + + private void checkInterrupt() { + if (Thread.interrupted()) { + throw new RuntimeException(new InterruptedException("Transaction execution interrupted")); + } + } +} diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java index 9eed2bff09e..5a9fd6030cd 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java @@ -112,6 +112,7 @@ private TransactionSelectionResult transactionSelectionResultForInvalidResult( private boolean isTransientValidationError(final TransactionInvalidReason invalidReason) { return invalidReason.equals(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE) || invalidReason.equals(TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE) - || invalidReason.equals(TransactionInvalidReason.NONCE_TOO_HIGH); + || invalidReason.equals(TransactionInvalidReason.NONCE_TOO_HIGH) + || invalidReason.equals(TransactionInvalidReason.EXECUTION_INTERRUPTED); } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index adcc3ee1e27..6eb03ece947 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -14,13 +14,15 @@ */ package org.hyperledger.besu.ethereum.blockcreation; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static org.awaitility.Awaitility.await; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME; +import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.EXECUTION_INTERRUPTED; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.NONCE_TOO_LOW; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT; -import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.INVALID_TX_EVALUATION_TOO_LONG; +import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT_INVALID_TX; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG; @@ -90,6 +92,7 @@ import org.hyperledger.besu.util.number.PositiveNumber; import java.math.BigInteger; +import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -185,6 +188,14 @@ public void setup() { when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); when(ethScheduler.scheduleBlockCreationTask(any(Runnable.class))) .thenAnswer(invocation -> CompletableFuture.runAsync(invocation.getArgument(0))); + when(ethScheduler.scheduleFutureTask(any(Runnable.class), any(Duration.class))) + .thenAnswer( + invocation -> { + final Duration delay = invocation.getArgument(1); + CompletableFuture.delayedExecutor(delay.toMillis(), MILLISECONDS) + .execute(invocation.getArgument(0)); + return null; + }); } protected abstract GenesisConfigFile getGenesisConfigFile(); @@ -982,9 +993,17 @@ private void internalBlockSelectionTimeoutSimulation( .TransactionEvaluationContext ctx = invocation.getArgument(0); if (ctx.getTransaction().equals(p)) { - Thread.sleep(t); + try { + Thread.sleep(t); + } catch (final InterruptedException e) { + return TransactionSelectionResult.invalidTransient(EXECUTION_INTERRUPTED.name()); + } } else { - Thread.sleep(fastProcessingTxTime); + try { + Thread.sleep(fastProcessingTxTime); + } catch (final InterruptedException e) { + return TransactionSelectionResult.invalidTransient(EXECUTION_INTERRUPTED.name()); + } } return SELECTED; }; @@ -1081,18 +1100,19 @@ public void subsetOfInvalidPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOv processingTooLate, postProcessingTooLate, 500, - BLOCK_SELECTION_TIMEOUT, - false, + BLOCK_SELECTION_TIMEOUT_INVALID_TX, + true, NONCE_TOO_LOW); } @ParameterizedTest @MethodSource("subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver") - public void invalidPendingTransactionsThatTakesTooLongToEvaluateIsDroppedFromThePool( - final boolean isPoa, - final boolean preProcessingTooLate, - final boolean processingTooLate, - final boolean postProcessingTooLate) { + public void + evaluationOfInvalidPendingTransactionThatTakesTooLongToEvaluateIsInterruptedAndPenalized( + final boolean isPoa, + final boolean preProcessingTooLate, + final boolean processingTooLate, + final boolean postProcessingTooLate) { internalBlockSelectionTimeoutSimulationInvalidTxs( isPoa, @@ -1100,8 +1120,8 @@ public void invalidPendingTransactionsThatTakesTooLongToEvaluateIsDroppedFromThe processingTooLate, postProcessingTooLate, 900, - INVALID_TX_EVALUATION_TOO_LONG, - true, + TX_EVALUATION_TOO_LONG, + false, NONCE_TOO_LOW); } @@ -1128,9 +1148,17 @@ private void internalBlockSelectionTimeoutSimulationInvalidTxs( .TransactionEvaluationContext ctx = invocation.getArgument(0); if (ctx.getTransaction().equals(p)) { - Thread.sleep(t); + try { + Thread.sleep(t); + } catch (final InterruptedException e) { + return TransactionSelectionResult.invalidTransient(EXECUTION_INTERRUPTED.name()); + } } else { - Thread.sleep(fastProcessingTxTime); + try { + Thread.sleep(fastProcessingTxTime); + } catch (final InterruptedException e) { + return TransactionSelectionResult.invalidTransient(EXECUTION_INTERRUPTED.name()); + } } return invalidSelectionResult; }; @@ -1199,7 +1227,7 @@ private void internalBlockSelectionTimeoutSimulationInvalidTxs( final TransactionSelectionResults results = selector.buildTransactionListForBlock(); - // no tx is selected since all are invalid + // no tx is selected since all are invalid or late assertThat(results.getSelectedTransactions()).isEmpty(); // all txs are not selected so wait until all are evaluated @@ -1350,7 +1378,12 @@ protected void ensureTransactionIsValid( .thenAnswer( invocation -> { if (processingTime > 0) { - Thread.sleep(processingTime); + try { + Thread.sleep(processingTime); + } catch (final InterruptedException e) { + return TransactionProcessingResult.invalid( + ValidationResult.invalid(EXECUTION_INTERRUPTED)); + } } return TransactionProcessingResult.successful( new ArrayList<>(), @@ -1375,7 +1408,12 @@ protected void ensureTransactionIsInvalid( .thenAnswer( invocation -> { if (processingTime > 0) { - Thread.sleep(processingTime); + try { + Thread.sleep(processingTime); + } catch (final InterruptedException e) { + return TransactionProcessingResult.invalid( + ValidationResult.invalid(EXECUTION_INTERRUPTED)); + } } return TransactionProcessingResult.invalid(ValidationResult.invalid(invalidReason)); }); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 91c964525e0..30a1ea8e762 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -599,6 +599,12 @@ public TransactionProcessingResult processTransaction( EMPTY_ADDRESS_SET, 0L); + final var cause = re.getCause(); + if (cause != null && cause instanceof InterruptedException) { + return TransactionProcessingResult.invalid( + ValidationResult.invalid(TransactionInvalidReason.EXECUTION_INTERRUPTED)); + } + LOG.error("Critical Exception Processing Transaction", re); return TransactionProcessingResult.invalid( ValidationResult.invalid( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java index 8273c556d91..f20cc8fce79 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java @@ -45,6 +45,7 @@ public enum TransactionInvalidReason { MAX_FEE_PER_GAS_BELOW_CURRENT_BASE_FEE, TX_FEECAP_EXCEEDED, INTERNAL_ERROR, + EXECUTION_INTERRUPTED, TX_POOL_DISABLED, INVALID_BLOBS, PLUGIN_TX_POOL_VALIDATOR, diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index bee57ab5aef..6d3a1f93a9a 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,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 = 'V/bdVbzJLjdwch266dHHuxIGwiCRhS4w3jDwHt4TWqg=' + knownHash = '5H+3gUzCwZtLByfnk11kf+kAPwykQ+WR+n3xWgyfsyY=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java index 66b1c1f2d65..1c35972a582 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java @@ -63,6 +63,7 @@ private enum BaseStatus implements Status { BLOBS_FULL(false, false, false), BLOCK_OCCUPANCY_ABOVE_THRESHOLD(true, false, false), BLOCK_SELECTION_TIMEOUT(true, false, false), + BLOCK_SELECTION_TIMEOUT_INVALID_TX(true, true, true), TX_EVALUATION_TOO_LONG(true, false, true), INVALID_TX_EVALUATION_TOO_LONG(true, true, true), INVALID_TRANSIENT(false, false, true), @@ -121,7 +122,11 @@ public boolean penalize() { public static final TransactionSelectionResult BLOCK_SELECTION_TIMEOUT = new TransactionSelectionResult(BaseStatus.BLOCK_SELECTION_TIMEOUT); - /** Transaction took too much to evaluate, but it was not invalid */ + /** There was no more time to add transaction to the block, and the transaction is invalid */ + public static final TransactionSelectionResult BLOCK_SELECTION_TIMEOUT_INVALID_TX = + new TransactionSelectionResult(BaseStatus.BLOCK_SELECTION_TIMEOUT_INVALID_TX); + + /** Transaction took too much to evaluate, but it was valid */ public static final TransactionSelectionResult TX_EVALUATION_TOO_LONG = new TransactionSelectionResult(BaseStatus.TX_EVALUATION_TOO_LONG);