[Plugin API] - TransactionSelector - Notify plugins when transaction is selected/rejected (#6005)

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
pull/6014/head
Gabriel-Trintinalia 1 year ago committed by GitHub
parent 573cb1bc43
commit e8a0428a27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java
  2. 42
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  3. 2
      plugin-api/build.gradle
  4. 13
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/txselection/TransactionSelector.java

@ -145,8 +145,7 @@ public class BlockTransactionSelector {
pendingTransaction -> {
final var res = evaluateTransaction(pendingTransaction);
if (!res.selected()) {
transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), res);
updateTransactionRejected(pendingTransaction, res);
}
return res;
});
@ -169,9 +168,10 @@ public class BlockTransactionSelector {
public TransactionSelectionResults evaluateTransactions(final List<Transaction> transactions) {
transactions.forEach(
transaction -> {
final var res = evaluateTransaction(new PendingTransaction.Local(transaction));
var pendingTransaction = new PendingTransaction.Local(transaction);
final var res = evaluateTransaction(pendingTransaction);
if (!res.selected()) {
transactionSelectionResults.updateNotSelected(transaction, res);
updateTransactionRejected(pendingTransaction, res);
}
});
return transactionSelectionResults;
@ -234,8 +234,7 @@ public class BlockTransactionSelector {
final long blobGasUsed =
blockSelectionContext.gasCalculator().blobGasCost(transaction.getBlobCount());
transactionSelectionResults.updateSelected(
transaction, receipt, gasUsedByTransaction, blobGasUsed);
updateTransactionSelected(pendingTransaction, receipt, gasUsedByTransaction, blobGasUsed);
LOG.atTrace()
.setMessage("Selected {} for block creation")
@ -245,6 +244,30 @@ public class BlockTransactionSelector {
return TransactionSelectionResult.SELECTED;
}
private void updateTransactionSelected(
final PendingTransaction pendingTransaction,
final TransactionReceipt receipt,
final long gasUsedByTransaction,
final long blobGasUsed) {
transactionSelectionResults.updateSelected(
pendingTransaction.getTransaction(), receipt, gasUsedByTransaction, blobGasUsed);
// notify external selector if any
externalTransactionSelector.onTransactionSelected(pendingTransaction);
}
private void updateTransactionRejected(
final PendingTransaction pendingTransaction,
final TransactionSelectionResult processingResult) {
transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), processingResult);
// notify external selector if any
externalTransactionSelector.onTransactionRejected(pendingTransaction);
}
/**
* This method evaluates a transaction by pre-processing it through a series of selectors. It
* first processes the transaction through internal selectors, and if the transaction is selected,

@ -19,6 +19,9 @@ import static org.assertj.core.api.Assertions.entry;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.GenesisConfigFile;
@ -33,6 +36,7 @@ import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockTransactionSelector;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AllAcceptingTransactionSelector;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
@ -84,6 +88,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
@ -659,6 +664,43 @@ public abstract class AbstractBlockTransactionSelectorTest {
.containsOnly(entry(notSelected, TransactionSelectionResult.invalidTransient("Invalid")));
}
@Test
public void transactionSelectionPluginShouldBeNotifiedWhenTransactionSelectionCompletes() {
final TransactionSelectorFactory transactionSelectorFactory =
mock(TransactionSelectorFactory.class);
TransactionSelector transactionSelector = spy(AllAcceptingTransactionSelector.INSTANCE);
when(transactionSelectorFactory.create()).thenReturn(transactionSelector);
final Transaction transaction = createTransaction(0, Wei.of(10), 21_000);
ensureTransactionIsValid(transaction, 21_000, 0);
final Transaction invalidTransaction = createTransaction(1, Wei.of(10), 21_000);
ensureTransactionIsInvalid(
invalidTransaction, TransactionInvalidReason.PLUGIN_TX_VALIDATOR_INVALIDATED);
transactionPool.addRemoteTransactions(List.of(transaction, invalidTransaction));
createBlockSelectorWithTxSelPlugin(
transactionProcessor,
createBlock(300_000),
Wei.ZERO,
AddressHelpers.ofValue(1),
Wei.ZERO,
MIN_OCCUPANCY_80_PERCENT,
transactionSelectorFactory)
.buildTransactionListForBlock();
ArgumentCaptor<PendingTransaction> argumentCaptor =
ArgumentCaptor.forClass(PendingTransaction.class);
verify(transactionSelector).onTransactionSelected(argumentCaptor.capture());
PendingTransaction selected = argumentCaptor.getValue();
assertThat(selected.getTransaction()).isEqualTo(transaction);
verify(transactionSelector).onTransactionRejected(argumentCaptor.capture());
PendingTransaction rejectedTransaction = argumentCaptor.getValue();
assertThat(rejectedTransaction.getTransaction()).isEqualTo(invalidTransaction);
}
@Test
public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() {
final ProcessableBlockHeader blockHeader = createBlock(5_000_000);

@ -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 = '8NVdDoCnMQiibEZUsZuemZU+wm3W1LPklcQkiKsriKs='
knownHash = '+7wo9cABKEFyYvjtpDFAOXqVKBAkffdnb433hT0VQ7I='
}
check.dependsOn('checkAPIChanges')

@ -43,4 +43,17 @@ public interface TransactionSelector {
*/
TransactionSelectionResult evaluateTransactionPostProcessing(
PendingTransaction pendingTransaction, TransactionProcessingResult processingResult);
/**
* Method called when a transaction is selected to be added to a block.
*
* @param pendingTransaction The transaction that has been selected.
*/
default void onTransactionSelected(final PendingTransaction pendingTransaction) {}
/**
* Method called when a transaction is rejected to be added to a block.
*
* @param pendingTransaction The transaction that has been rejected.
*/
default void onTransactionRejected(final PendingTransaction pendingTransaction) {}
}

Loading…
Cancel
Save