New option tx-pool-min-gas-price to set a lower bound when accepting txs to the pool (#6098)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
Fabio Di Fabio
2023-11-20 12:49:17 +01:00
committed by GitHub
parent f01e4a20f9
commit eaf56820f5
31 changed files with 215 additions and 196 deletions

View File

@@ -9,6 +9,7 @@
### Additions and Improvements
- 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)
## 23.10.2

View File

@@ -2830,6 +2830,23 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
txPoolConfBuilder.priceBump(Percentage.ZERO);
}
if (getMiningParameters().getMinTransactionGasPrice().lessThan(txPoolConf.getMinGasPrice())) {
if (transactionPoolOptions.isMinGasPriceSet(commandLine)) {
throw new ParameterException(
commandLine, "tx-pool-min-gas-price cannot be greater than the value of min-gas-price");
} else {
// for backward compatibility, if tx-pool-min-gas-price is not set, we adjust its value
// to be the same as min-gas-price, so the behavior is as before this change, and we notify
// the user of the change
logger.warn(
"Forcing tx-pool-min-gas-price="
+ getMiningParameters().getMinTransactionGasPrice().toDecimalString()
+ ", since it cannot be greater than the value of min-gas-price");
txPoolConfBuilder.minGasPrice(getMiningParameters().getMinTransactionGasPrice());
}
}
return txPoolConfBuilder.build();
}

View File

@@ -54,6 +54,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG =
"--strict-tx-replay-protection-enabled";
private static final String TX_POOL_PRIORITY_SENDERS = "--tx-pool-priority-senders";
private static final String TX_POOL_MIN_GAS_PRICE = "--tx-pool-min-gas-price";
@CommandLine.Option(
names = {TX_POOL_IMPLEMENTATION},
@@ -122,6 +123,15 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
arity = "1..*")
private Set<Address> prioritySenders = TransactionPoolConfiguration.DEFAULT_PRIORITY_SENDERS;
@CommandLine.Option(
names = {TX_POOL_MIN_GAS_PRICE},
paramLabel = "<Wei>",
description =
"Transactions with gas price (in Wei) lower than this minimum will not be accepted into the txpool"
+ "(not to be confused with min-gas-price, that is applied on block creation) (default: ${DEFAULT-VALUE})",
arity = "1")
private Wei minGasPrice = TransactionPoolConfiguration.DEFAULT_TX_POOL_MIN_GAS_PRICE;
@CommandLine.ArgGroup(
validate = false,
heading = "@|bold Tx Pool Layered Implementation Options|@%n")
@@ -257,6 +267,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
options.saveFile = config.getSaveFile();
options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled();
options.prioritySenders = config.getPrioritySenders();
options.minGasPrice = config.getMinGasPrice();
options.layeredOptions.txPoolLayerMaxCapacity =
config.getPendingTransactionsLayerMaxCapacityBytes();
options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions();
@@ -312,6 +323,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
.saveFile(saveFile)
.strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled)
.prioritySenders(prioritySenders)
.minGasPrice(minGasPrice)
.pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity)
.maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized)
.maxFutureBySender(layeredOptions.txPoolMaxFutureBySender)
@@ -340,4 +352,14 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
public boolean isPriceBumpSet(final CommandLine commandLine) {
return CommandLineUtils.isOptionSet(commandLine, TransactionPoolOptions.TX_POOL_PRICE_BUMP);
}
/**
* Is min gas price option set?
*
* @param commandLine the command line
* @return true if tx-pool-min-gas-price is set
*/
public boolean isMinGasPriceSet(final CommandLine commandLine) {
return CommandLineUtils.isOptionSet(commandLine, TransactionPoolOptions.TX_POOL_MIN_GAS_PRICE);
}
}

View File

@@ -722,7 +722,6 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
clock,
metricsSystem,
syncState,
miningParameters,
transactionPoolConfiguration,
pluginTransactionValidatorFactory,
besuComponent.map(BesuComponent::getBlobCache).orElse(new BlobCache()));

View File

@@ -5248,6 +5248,31 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void txpoolWhenNotSetForceTxPoolMinGasPriceToZeroWhenMinGasPriceZero() {
parseCommand("--min-gas-price", "0");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
final Wei txPoolMinGasPrice = transactionPoolConfigCaptor.getValue().getMinGasPrice();
assertThat(txPoolMinGasPrice).isEqualTo(Wei.ZERO);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
verify(mockLogger, atLeast(1))
.warn(
contains(
"Forcing tx-pool-min-gas-price=0, since it cannot be greater than the value of min-gas-price"));
}
@Test
public void txpoolTxPoolMinGasPriceMustNotBeGreaterThanMinGasPriceZero() {
parseCommand("--min-gas-price", "100", "--tx-pool-min-gas-price", "101");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("tx-pool-min-gas-price cannot be greater than the value of min-gas-price");
}
@Test
public void snapsyncHealingOptionShouldBeDisabledByDefault() {
final TestBesuCommand besuCommand = parseCommand();

View File

@@ -33,8 +33,6 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
@@ -147,7 +145,10 @@ public class BesuEventsImplTest {
blockBroadcaster = new BlockBroadcaster(mockEthContext);
syncState = new SyncState(blockchain, mockEthPeers);
TransactionPoolConfiguration txPoolConfig =
ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build();
ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(1)
.minGasPrice(Wei.ZERO)
.build();
transactionPool =
TransactionPoolFactory.createTransactionPool(
@@ -157,10 +158,6 @@ public class BesuEventsImplTest {
TestClock.system(ZoneId.systemDefault()),
new NoOpMetricsSystem(),
syncState,
ImmutableMiningParameters.builder()
.mutableInitValues(
MutableInitValues.builder().minTransactionGasPrice(Wei.ZERO).build())
.build(),
txPoolConfig,
null,
new BlobCache());

View File

@@ -188,6 +188,7 @@ tx-pool-max-future-by-sender=321
tx-pool-retention-hours=999
tx-pool-max-size=1234
tx-pool-limit-by-account-percentage=0.017
tx-pool-min-gas-price=1000
# Revert Reason
revert-reason-enabled=false

View File

@@ -238,7 +238,6 @@ public class CliqueBlockCreatorTest {
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem),
conf,
null);

View File

@@ -222,7 +222,6 @@ public class CliqueMinerExecutorTest {
cliqueProtocolContext,
mock(TransactionBroadcaster.class),
cliqueEthContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem),
conf,
null);

View File

@@ -362,7 +362,6 @@ public class TestContextBuilder {
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
miningParams,
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -146,7 +146,6 @@ public class BftBlockCreatorTest {
protContext,
mock(TransactionBroadcaster.class),
ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -227,7 +227,6 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -450,7 +450,6 @@ public class TestContextBuilder {
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
miningParams,
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -44,7 +44,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@@ -119,7 +118,6 @@ public class EthGetFilterChangesIntegrationTest {
protocolContext,
batchAddedListener,
ethContext,
MiningParameters.newDefault(),
new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT,
null);

View File

@@ -44,7 +44,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@@ -119,7 +118,6 @@ public class EthGetFilterChangesIntegrationTest {
protocolContext,
batchAddedListener,
ethContext,
MiningParameters.newDefault(),
new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT,
null);

View File

@@ -383,7 +383,6 @@ abstract class AbstractBlockCreatorTest {
executionContextTestFixture.getProtocolContext(),
mock(TransactionBroadcaster.class),
ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf,
null);

View File

@@ -181,7 +181,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
protected abstract ProtocolSchedule createProtocolSchedule();
protected abstract TransactionPool createTransactionPool(final MiningParameters miningParameters);
protected abstract TransactionPool createTransactionPool();
private Boolean isCancelled() {
return false;
@@ -1026,7 +1026,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
final Wei blobGasPrice,
final PluginTransactionSelectorFactory transactionSelectorFactory) {
transactionPool = createTransactionPool(miningParameters);
transactionPool = createTransactionPool();
return createBlockSelector(
miningParameters,

View File

@@ -20,7 +20,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
@@ -62,11 +62,12 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
}
@Override
protected TransactionPool createTransactionPool(final MiningParameters miningParameters) {
protected TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f))
.minGasPrice(Wei.ONE)
.build();
final PendingTransactions pendingTransactions =
@@ -86,7 +87,6 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -74,11 +74,12 @@ public class LondonFeeMarketBlockTransactionSelectorTest
}
@Override
protected TransactionPool createTransactionPool(final MiningParameters miningParameters) {
protected TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f))
.minGasPrice(Wei.ONE)
.build();
final PendingTransactions pendingTransactions =
new BaseFeePendingTransactionsSorter(
@@ -94,7 +95,6 @@ public class LondonFeeMarketBlockTransactionSelectorTest
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -332,7 +332,6 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
executionContextTestFixture.getProtocolContext(),
mock(TransactionBroadcaster.class),
ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem),
poolConf,
null);

View File

@@ -52,7 +52,7 @@ public class PoWMinerExecutorTest {
public void startingMiningWithoutCoinbaseThrowsException() {
final MiningParameters miningParameters = MiningParameters.newDefault();
final TransactionPool transactionPool = createTransactionPool(miningParameters);
final TransactionPool transactionPool = createTransactionPool();
final PoWMinerExecutor executor =
new PoWMinerExecutor(
@@ -73,7 +73,7 @@ public class PoWMinerExecutorTest {
public void settingCoinbaseToNullThrowsException() {
final MiningParameters miningParameters = MiningParameters.newDefault();
final TransactionPool transactionPool = createTransactionPool(miningParameters);
final TransactionPool transactionPool = createTransactionPool();
final PoWMinerExecutor executor =
new PoWMinerExecutor(
@@ -96,7 +96,7 @@ public class PoWMinerExecutorTest {
return blockHeader;
}
private TransactionPool createTransactionPool(final MiningParameters miningParameters) {
private TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build();
final GasPricePendingTransactionsSorter pendingTransactions =
@@ -116,7 +116,6 @@ public class PoWMinerExecutorTest {
mock(ProtocolContext.class),
mock(TransactionBroadcaster.class),
ethContext,
miningParameters,
new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf,
null);

View File

@@ -170,7 +170,6 @@ public abstract class AbstractIsolationTests {
protocolContext,
mock(TransactionBroadcaster.class),
ethContext,
mock(MiningParameters.class),
txPoolMetrics,
poolConfiguration,
null);

View File

@@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
import org.hyperledger.besu.ethereum.chain.BlockAddedObserver;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
@@ -100,7 +99,6 @@ public class TransactionPool implements BlockAddedObserver {
private final ProtocolContext protocolContext;
private final EthContext ethContext;
private final TransactionBroadcaster transactionBroadcaster;
private final MiningParameters miningParameters;
private final TransactionPoolMetrics metrics;
private final TransactionPoolConfiguration configuration;
private final AtomicBoolean isPoolEnabled = new AtomicBoolean(false);
@@ -118,7 +116,6 @@ public class TransactionPool implements BlockAddedObserver {
final ProtocolContext protocolContext,
final TransactionBroadcaster transactionBroadcaster,
final EthContext ethContext,
final MiningParameters miningParameters,
final TransactionPoolMetrics metrics,
final TransactionPoolConfiguration configuration,
final PluginTransactionValidatorFactory pluginTransactionValidatorFactory) {
@@ -127,7 +124,6 @@ public class TransactionPool implements BlockAddedObserver {
this.protocolContext = protocolContext;
this.ethContext = ethContext;
this.transactionBroadcaster = transactionBroadcaster;
this.miningParameters = miningParameters;
this.metrics = metrics;
this.configuration = configuration;
this.pluginTransactionValidator =
@@ -289,7 +285,7 @@ public class TransactionPool implements BlockAddedObserver {
private boolean isMaxGasPriceBelowConfiguredMinGasPrice(final Transaction transaction) {
return getMaxGasPrice(transaction)
.map(g -> g.lessThan(miningParameters.getMinTransactionGasPrice()))
.map(g -> g.lessThan(configuration.getMinGasPrice()))
.orElse(true);
}
@@ -510,11 +506,9 @@ public class TransactionPool implements BlockAddedObserver {
}
}
if (hasPriority) {
// allow priority transactions to be below minGas as long as we are mining
// or at least gas price is above the configured floor
if ((!miningParameters.isMiningEnabled()
&& isMaxGasPriceBelowConfiguredMinGasPrice(transaction))
|| !feeMarket.satisfiesFloorTxFee(transaction)) {
// allow priority transactions to be below minGas as long as the gas price is above the
// configured floor
if (!feeMarket.satisfiesFloorTxFee(transaction)) {
return TransactionInvalidReason.GAS_PRICE_TOO_LOW;
}
} else {
@@ -522,7 +516,7 @@ public class TransactionPool implements BlockAddedObserver {
LOG.atTrace()
.setMessage("Discard transaction {} below min gas price {}")
.addArgument(transaction::toTraceLog)
.addArgument(miningParameters::getMinTransactionGasPrice)
.addArgument(configuration::getMinGasPrice)
.log();
return TransactionInvalidReason.GAS_PRICE_TOO_LOW;
}

View File

@@ -69,6 +69,7 @@ public interface TransactionPoolConfiguration {
int DEFAULT_MAX_FUTURE_BY_SENDER = 200;
Implementation DEFAULT_TX_POOL_IMPLEMENTATION = Implementation.LAYERED;
Set<Address> DEFAULT_PRIORITY_SENDERS = Set.of();
Wei DEFAULT_TX_POOL_MIN_GAS_PRICE = Wei.of(1000);
TransactionPoolConfiguration DEFAULT = ImmutableTransactionPoolConfiguration.builder().build();
@@ -147,6 +148,11 @@ public interface TransactionPoolConfiguration {
return DEFAULT_PRIORITY_SENDERS;
}
@Value.Default
default Wei getMinGasPrice() {
return DEFAULT_TX_POOL_MIN_GAS_PRICE;
}
@Value.Default
default Unstable getUnstable() {
return Unstable.DEFAULT;

View File

@@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.eth.transactions;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.messages.EthPV62;
import org.hyperledger.besu.ethereum.eth.messages.EthPV65;
@@ -54,7 +53,6 @@ public class TransactionPoolFactory {
final Clock clock,
final MetricsSystem metricsSystem,
final SyncState syncState,
final MiningParameters miningParameters,
final TransactionPoolConfiguration transactionPoolConfiguration,
final PluginTransactionValidatorFactory pluginTransactionValidatorFactory,
final BlobCache blobCache) {
@@ -75,7 +73,6 @@ public class TransactionPoolFactory {
clock,
metrics,
syncState,
miningParameters,
transactionPoolConfiguration,
transactionTracker,
transactionsMessageSender,
@@ -91,7 +88,6 @@ public class TransactionPoolFactory {
final Clock clock,
final TransactionPoolMetrics metrics,
final SyncState syncState,
final MiningParameters miningParameters,
final TransactionPoolConfiguration transactionPoolConfiguration,
final PeerTransactionTracker transactionTracker,
final TransactionsMessageSender transactionsMessageSender,
@@ -117,7 +113,6 @@ public class TransactionPoolFactory {
transactionsMessageSender,
newPooledTransactionHashesMessageSender),
ethContext,
miningParameters,
metrics,
transactionPoolConfiguration,
pluginTransactionValidatorFactory);

View File

@@ -36,7 +36,6 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
@@ -1117,7 +1116,6 @@ public final class EthProtocolManagerTest {
TestClock.system(ZoneId.systemDefault()),
metricsSystem,
new SyncState(blockchain, ethManager.ethContext().getEthPeers()),
MiningParameters.newDefault(),
TransactionPoolConfiguration.DEFAULT,
null,
new BlobCache())

View File

@@ -25,7 +25,6 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@@ -136,7 +135,6 @@ public abstract class AbstractMessageTaskTest<T, R> {
TestClock.system(ZoneId.systemDefault()),
metricsSystem,
syncState,
MiningParameters.newDefault(),
TransactionPoolConfiguration.DEFAULT,
null,
new BlobCache());

View File

@@ -60,7 +60,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
@@ -102,6 +101,7 @@ import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -110,6 +110,8 @@ import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
@@ -133,9 +135,6 @@ public abstract class AbstractTransactionPoolTest {
@Mock protected PendingTransactionAddedListener listener;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
protected MiningParameters miningParameters;
@Mock protected TransactionsMessageSender transactionsMessageSender;
@Mock protected NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender;
@Mock protected ProtocolSpec protocolSpec;
@@ -253,11 +252,10 @@ public abstract class AbstractTransactionPoolTest {
transactionPool = createTransactionPool();
blockchain.observeBlockAdded(transactionPool);
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.of(2));
}
protected TransactionPool createTransactionPool() {
return createTransactionPool(b -> {});
return createTransactionPool(b -> b.minGasPrice(Wei.of(2)));
}
protected TransactionPool createTransactionPool(
@@ -290,7 +288,6 @@ public abstract class AbstractTransactionPoolTest {
protocolContext,
transactionBroadcaster,
ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem),
poolConfig,
pluginTransactionValidatorFactory);
@@ -625,7 +622,8 @@ public abstract class AbstractTransactionPoolTest {
@ValueSource(booleans = {true, false})
public void shouldNotNotifyBatchListenerWhenLocalTransactionDoesNotReplaceExisting(
final boolean noLocalPriority) {
transactionPool = createTransactionPool(b -> b.noLocalPriority(noLocalPriority));
transactionPool =
createTransactionPool(b -> b.minGasPrice(Wei.of(2)).noLocalPriority(noLocalPriority));
final Transaction transaction0a = createTransaction(0, Wei.of(10));
final Transaction transaction0b = createTransaction(0, Wei.of(9));
@@ -792,58 +790,6 @@ public abstract class AbstractTransactionPoolTest {
addAndAssertRemoteTransactionsValid(hasPriority, remoteTransaction);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldRejectZeroGasPriceLocalTransactionWhenNotMining(final boolean noLocalPriority) {
transactionPool = createTransactionPool(b -> b.noLocalPriority(noLocalPriority));
when(miningParameters.isMiningEnabled()).thenReturn(false);
final Transaction transaction = createTransaction(0, Wei.ZERO);
givenTransactionIsValid(transaction);
addAndAssertTransactionViaApiInvalid(transaction, GAS_PRICE_TOO_LOW);
}
@Test
@DisabledIf("isBaseFeeMarket")
public void shouldAcceptZeroGasPriceFrontierLocalPriorityTransactionsWhenMining() {
transactionPool = createTransactionPool(b -> b.noLocalPriority(false));
when(miningParameters.isMiningEnabled()).thenReturn(true);
final Transaction transaction = createTransaction(0, Wei.ZERO);
givenTransactionIsValid(transaction);
addAndAssertTransactionViaApiValid(transaction, false);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldRejectZeroGasPriceRemoteTransactionWhenNotMining(final boolean hasPriority) {
final Transaction transaction = createTransaction(0, Wei.ZERO);
final Set<Address> prioritySenders = hasPriority ? Set.of(transaction.getSender()) : Set.of();
transactionPool = createTransactionPool(b -> b.prioritySenders(prioritySenders));
when(miningParameters.isMiningEnabled()).thenReturn(false);
givenTransactionIsValid(transaction);
addAndAssertRemoteTransactionInvalid(transaction);
}
@Test
@DisabledIf("isBaseFeeMarket")
public void shouldAcceptZeroGasPriceFrontierRemotePriorityTransactionsWhenMining() {
final Transaction transaction = createTransaction(0, Wei.ZERO);
transactionPool =
createTransactionPool(b -> b.prioritySenders(Set.of(transaction.getSender())));
when(miningParameters.isMiningEnabled()).thenReturn(true);
givenTransactionIsValid(transaction);
addAndAssertRemoteTransactionsValid(true, transaction);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void transactionNotRejectedByPluginShouldBeAdded(final boolean noLocalPriority) {
@@ -998,54 +944,104 @@ public abstract class AbstractTransactionPoolTest {
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisabledIf("isBaseFeeMarket")
public void shouldAcceptZeroGasPriceTransactionWhenMinGasPriceIsZero(
final boolean noLocalPriority) {
transactionPool = createTransactionPool(b -> b.noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
public void shouldAcceptZeroGasPriceFrontierPriorityTransactions(final boolean isLocal) {
final Transaction transaction = createFrontierTransaction(0, Wei.ZERO);
transactionPool =
createTransactionPool(b -> b.prioritySenders(List.of(transaction.getSender())));
givenTransactionIsValid(transaction);
if (isLocal) {
addAndAssertTransactionViaApiValid(transaction, false);
} else {
addAndAssertRemoteTransactionsValid(true, transaction);
}
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldRejectZeroGasPriceNoPriorityTransaction(final boolean isLocal) {
final Transaction transaction = createTransaction(0, Wei.ZERO);
transactionPool = createTransactionPool(b -> b.noLocalPriority(true));
givenTransactionIsValid(transaction);
if (isLocal) {
addAndAssertTransactionViaApiInvalid(transaction, GAS_PRICE_TOO_LOW);
} else {
addAndAssertRemoteTransactionInvalid(transaction);
}
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisabledIf("isBaseFeeMarket")
public void shouldAcceptZeroGasPriceNoPriorityTransactionWhenMinGasPriceIsZero(
final boolean isLocal) {
transactionPool = createTransactionPool(b -> b.minGasPrice(Wei.ZERO).noLocalPriority(true));
final Transaction transaction = createTransaction(0, Wei.ZERO);
givenTransactionIsValid(transaction);
addAndAssertTransactionViaApiValid(transaction, noLocalPriority);
if (isLocal) {
addAndAssertTransactionViaApiValid(transaction, true);
} else {
addAndAssertRemoteTransactionsValid(false, transaction);
}
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
@MethodSource("provideHasPriorityAndIsLocal")
public void shouldAcceptZeroGasPriceFrontierTxsWhenMinGasPriceIsZeroAndLondonWithZeroBaseFee(
final boolean noLocalPriority) {
transactionPool = createTransactionPool(b -> b.noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0, Optional.of(Wei.ZERO)));
whenBlockBaseFeeIs(Wei.ZERO);
final boolean hasPriority, final boolean isLocal) {
final Transaction frontierTransaction = createFrontierTransaction(0, Wei.ZERO);
givenTransactionIsValid(frontierTransaction);
addAndAssertTransactionViaApiValid(frontierTransaction, noLocalPriority);
internalAcceptZeroGasPriceTxsWhenMinGasPriceIsZeroAndZeroBaseFee(
hasPriority, isLocal, frontierTransaction);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
@MethodSource("provideHasPriorityAndIsLocal")
public void shouldAcceptZeroGasPrice1559TxsWhenMinGasPriceIsZeroAndLondonWithZeroBaseFee(
final boolean noLocalPriority) {
transactionPool = createTransactionPool(b -> b.noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
final boolean hasPriority, final boolean isLocal) {
final Transaction transaction = createTransactionBaseFeeMarket(0, Wei.ZERO);
internalAcceptZeroGasPriceTxsWhenMinGasPriceIsZeroAndZeroBaseFee(
hasPriority, isLocal, transaction);
}
private void internalAcceptZeroGasPriceTxsWhenMinGasPriceIsZeroAndZeroBaseFee(
final boolean hasPriority, final boolean isLocal, final Transaction transaction) {
transactionPool =
createTransactionPool(
b -> {
b.minGasPrice(Wei.ZERO);
if (hasPriority) {
b.prioritySenders(List.of(transaction.getSender()));
} else {
b.noLocalPriority(true);
}
});
when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0, Optional.of(Wei.ZERO)));
whenBlockBaseFeeIs(Wei.ZERO);
final Transaction transaction = createTransaction(0, Wei.ZERO);
givenTransactionIsValid(transaction);
addAndAssertTransactionViaApiValid(transaction, noLocalPriority);
if (isLocal) {
addAndAssertTransactionViaApiValid(transaction, !hasPriority);
} else {
addAndAssertRemoteTransactionsValid(hasPriority, transaction);
}
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void samePriceTxReplacementWhenPriceBumpIsZeroFrontier(final boolean noLocalPriority) {
transactionPool =
createTransactionPool(b -> b.priceBump(Percentage.ZERO).noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
createTransactionPool(
b ->
b.priceBump(Percentage.ZERO)
.noLocalPriority(noLocalPriority)
.minGasPrice(Wei.ZERO));
final Transaction transaction1a =
createBaseTransactionGasPriceMarket(0)
@@ -1081,8 +1077,11 @@ public abstract class AbstractTransactionPoolTest {
@EnabledIf("isBaseFeeMarket")
public void replaceSamePriceTxWhenPriceBumpIsZeroLondon(final boolean noLocalPriority) {
transactionPool =
createTransactionPool(b -> b.priceBump(Percentage.ZERO).noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
createTransactionPool(
b ->
b.priceBump(Percentage.ZERO)
.noLocalPriority(noLocalPriority)
.minGasPrice(Wei.ZERO));
final Transaction transaction1a =
createBaseTransactionBaseFeeMarket(0)
@@ -1120,8 +1119,11 @@ public abstract class AbstractTransactionPoolTest {
@EnabledIf("isBaseFeeMarket")
public void replaceSamePriceTxWhenPriceBumpIsZeroLondonToFrontier(final boolean noLocalPriority) {
transactionPool =
createTransactionPool(b -> b.priceBump(Percentage.ZERO).noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
createTransactionPool(
b ->
b.priceBump(Percentage.ZERO)
.noLocalPriority(noLocalPriority)
.minGasPrice(Wei.ZERO));
final Transaction transaction1a =
createBaseTransactionBaseFeeMarket(0)
@@ -1158,8 +1160,11 @@ public abstract class AbstractTransactionPoolTest {
@EnabledIf("isBaseFeeMarket")
public void replaceSamePriceTxWhenPriceBumpIsZeroFrontierToLondon(final boolean noLocalPriority) {
transactionPool =
createTransactionPool(b -> b.priceBump(Percentage.ZERO).noLocalPriority(noLocalPriority));
when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ZERO);
createTransactionPool(
b ->
b.priceBump(Percentage.ZERO)
.noLocalPriority(noLocalPriority)
.minGasPrice(Wei.ZERO));
final Transaction transaction1a =
createBaseTransactionGasPriceMarket(0)
@@ -1191,79 +1196,56 @@ public abstract class AbstractTransactionPoolTest {
.containsOnly(transaction1b);
}
@Test
public void shouldAcceptBaseFeeFloorGasPriceFrontierLocalPriorityTransactionsWhenMining() {
transactionPool = createTransactionPool(b -> b.noLocalPriority(false));
final Transaction frontierTransaction = createFrontierTransaction(0, BASE_FEE_FLOOR);
givenTransactionIsValid(frontierTransaction);
addAndAssertTransactionViaApiValid(frontierTransaction, false);
private static Stream<Arguments> provideHasPriorityAndIsLocal() {
return Stream.of(
Arguments.of(true, true),
Arguments.of(true, false),
Arguments.of(false, true),
Arguments.of(false, false));
}
@Test
public void shouldAcceptBaseFeeFloorGasPriceFrontierRemotePriorityTransactionsWhenMining() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldAcceptBaseFeeFloorGasPriceFrontierPriorityTransactions(final boolean isLocal) {
final Transaction frontierTransaction = createFrontierTransaction(0, BASE_FEE_FLOOR);
transactionPool =
createTransactionPool(b -> b.prioritySenders(Set.of(frontierTransaction.getSender())));
createTransactionPool(b -> b.prioritySenders(List.of(frontierTransaction.getSender())));
givenTransactionIsValid(frontierTransaction);
addAndAssertRemoteTransactionsValid(frontierTransaction);
if (isLocal) {
addAndAssertTransactionViaApiValid(frontierTransaction, false);
} else {
addAndAssertRemoteTransactionsValid(true, frontierTransaction);
}
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldRejectRemote1559TxsWhenMaxFeePerGasBelowMinGasPrice(final boolean hasPriority) {
public void shouldRejectNoPriorityTxsWhenMaxFeePerGasBelowMinGasPrice(final boolean isLocal) {
final Wei genesisBaseFee = Wei.of(100L);
final Wei minGasPrice = Wei.of(200L);
final Wei lastBlockBaseFee = minGasPrice.add(50L);
final Wei txMaxFeePerGas = minGasPrice.subtract(1L);
assertThat(
add1559TxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, false, hasPriority))
addTxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, isLocal, false))
.isZero();
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldAcceptRemote1559TxsWhenMaxFeePerGasIsAtLeastEqualToMinGasPrice(
final boolean hasPriority) {
public void shouldAcceptNoPriorityTxsWhenMaxFeePerGasIsAtLeastEqualToMinGasPrice(
final boolean isLocal) {
final Wei genesisBaseFee = Wei.of(100L);
final Wei minGasPrice = Wei.of(200L);
final Wei lastBlockBaseFee = minGasPrice.add(50L);
final Wei txMaxFeePerGas = minGasPrice;
assertThat(
add1559TxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, false, hasPriority))
.isEqualTo(1);
}
@Test
public void shouldRejectLocal1559TxsWhenMaxFeePerGasBelowMinGasPrice() {
final Wei genesisBaseFee = Wei.of(100L);
final Wei minGasPrice = Wei.of(200L);
final Wei lastBlockBaseFee = minGasPrice.add(50L);
final Wei txMaxFeePerGas = minGasPrice.subtract(1L);
assertThat(
add1559TxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, true, true))
.isZero();
}
@Test
public void shouldAcceptLocal1559TxsWhenMaxFeePerGasIsAtLeastEqualToMinMinGasPrice() {
final Wei genesisBaseFee = Wei.of(100L);
final Wei minGasPrice = Wei.of(200L);
final Wei lastBlockBaseFee = minGasPrice.add(50L);
final Wei txMaxFeePerGas = minGasPrice;
assertThat(
add1559TxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, true, true))
addTxAndGetPendingTxsCount(
genesisBaseFee, minGasPrice, lastBlockBaseFee, txMaxFeePerGas, isLocal, false))
.isEqualTo(1);
}
@@ -1470,22 +1452,26 @@ public abstract class AbstractTransactionPoolTest {
.createTransaction(KEY_PAIR1);
}
protected int add1559TxAndGetPendingTxsCount(
protected int addTxAndGetPendingTxsCount(
final Wei genesisBaseFee,
final Wei minGasPrice,
final Wei lastBlockBaseFee,
final Wei txMaxFeePerGas,
final boolean isLocal,
final boolean hasPriority) {
when(miningParameters.getMinTransactionGasPrice()).thenReturn(minGasPrice);
when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0, Optional.of(genesisBaseFee)));
whenBlockBaseFeeIs(lastBlockBaseFee);
final Transaction transaction = createTransaction(0, txMaxFeePerGas);
if (hasPriority) {
transactionPool =
createTransactionPool(b -> b.prioritySenders(Set.of(transaction.getSender())));
createTransactionPool(
b -> b.minGasPrice(minGasPrice).prioritySenders(Set.of(transaction.getSender())));
} else {
transactionPool =
createTransactionPool(b -> b.minGasPrice(minGasPrice).noLocalPriority(true));
}
givenTransactionIsValid(transaction);
if (isLocal) {

View File

@@ -31,7 +31,6 @@ import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
@@ -162,7 +161,6 @@ public class TestNode implements Closeable {
TestClock.system(ZoneId.systemDefault()),
metricsSystem,
syncState,
MiningParameters.newDefault(),
TransactionPoolConfiguration.DEFAULT,
null,
new BlobCache());

View File

@@ -31,7 +31,6 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BlockAddedObserver;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@@ -240,7 +239,6 @@ public class TransactionPoolFactoryTest {
TestClock.fixed(),
new TransactionPoolMetrics(new NoOpMetricsSystem()),
syncState,
MiningParameters.newDefault(),
ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(1)
.pendingTxRetentionPeriod(1)
@@ -350,7 +348,6 @@ public class TransactionPoolFactoryTest {
TestClock.fixed(),
new NoOpMetricsSystem(),
syncState,
MiningParameters.newDefault(),
ImmutableTransactionPoolConfiguration.builder()
.txPoolImplementation(implementation)
.txPoolMaxSize(1)

View File

@@ -251,7 +251,6 @@ public class RetestethContext {
retestethClock,
metricsSystem,
syncState,
miningParameters,
transactionPoolConfiguration,
null,
new BlobCache());