diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/transactions/TransactionPoolFactory.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/transactions/TransactionPoolFactory.java index 7b9fa49ad6..28243225fc 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/transactions/TransactionPoolFactory.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/transactions/TransactionPoolFactory.java @@ -27,9 +27,10 @@ public class TransactionPoolFactory { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, - final Clock clock) { + final Clock clock, + final int maxPendingTransactions) { final PendingTransactions pendingTransactions = - new PendingTransactions(PendingTransactions.MAX_PENDING_TRANSACTIONS, clock); + new PendingTransactions(maxPendingTransactions, clock); final PeerTransactionTracker transactionTracker = new PeerTransactionTracker(); final TransactionsMessageSender transactionsMessageSender = diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java index d4d84704d7..ad28a40881 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockBody; import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; @@ -1015,7 +1016,11 @@ public final class EthProtocolManagerTest { // Create a transaction pool. This has a side effect of registring a listener for the // transactions message. TransactionPoolFactory.createTransactionPool( - protocolSchedule, protocolContext, ethManager.ethContext(), TestClock.fixed()); + protocolSchedule, + protocolContext, + ethManager.ethContext(), + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); // Send just a transaction message. final PeerConnection peer = setupPeer(ethManager, (cap, msg, connection) -> {}); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java index e2f62cd8a9..9a203b93bf 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.chain.GenesisState; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.core.BlockHashFunction; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.TransactionPool; @@ -133,7 +134,11 @@ public class TestNode implements Closeable { final EthContext ethContext = ethProtocolManager.ethContext(); transactionPool = TransactionPoolFactory.createTransactionPool( - protocolSchedule, protocolContext, ethContext, TestClock.fixed()); + protocolSchedule, + protocolContext, + ethContext, + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); networkRunner.start(); selfPeer = new DefaultPeer(id(), endpoint()); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java index 6b083ec13a..8d2211496b 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -40,6 +40,7 @@ import tech.pegasys.pantheon.controller.KeyPairUtil; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.MiningParameters; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; @@ -458,6 +459,14 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { "The address to which the privacy pre-compiled contract will be mapped to (default: ${DEFAULT-VALUE})") private final Integer privacyPrecompiledAddress = Address.PRIVACY; + @Option( + names = {"--tx-pool-max-size"}, + paramLabel = MANDATORY_INTEGER_FORMAT_HELP, + description = + "Maximum number of pending transactions that will be kept in the transaction pool (default: ${DEFAULT-VALUE})", + arity = "1") + private final Integer txPoolMaxSize = PendingTransactions.MAX_PENDING_TRANSACTIONS; + // Inner class so we can get to loggingLevel. public class PantheonExceptionHandler extends CommandLine.AbstractHandler, PantheonExceptionHandler> @@ -643,6 +652,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { .miningParameters( new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled)) .devMode(NetworkName.DEV.equals(getNetwork())) + .maxPendingTransactions(txPoolMaxSize) .nodePrivateKeyFile(nodePrivateKeyFile()) .metricsSystem(metricsSystem.get()) .privacyParameters(privacyParameters()) diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java index c03dcb3c76..02c7fe1122 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java @@ -40,6 +40,7 @@ public class PantheonControllerBuilder { private File nodePrivateKeyFile; private MetricsSystem metricsSystem; private PrivacyParameters privacyParameters; + private Integer maxPendingTransactions; public PantheonControllerBuilder synchronizerConfiguration( final SynchronizerConfiguration synchronizerConfiguration) { @@ -77,6 +78,11 @@ public class PantheonControllerBuilder { return this; } + public PantheonControllerBuilder maxPendingTransactions(final Integer maxPendingTransactions) { + this.maxPendingTransactions = maxPendingTransactions; + return this; + } + public PantheonControllerBuilder privacyParameters(final PrivacyParameters privacyParameters) { this.privacyParameters = privacyParameters; return this; @@ -108,6 +114,7 @@ public class PantheonControllerBuilder { metricsSystem, privacyParameters, homePath, - clock); + clock, + maxPendingTransactions); } } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java index 9c628b84ab..5d25b6c048 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java @@ -111,7 +111,8 @@ public class CliquePantheonController implements PantheonController protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); @@ -168,7 +169,11 @@ public class IbftLegacyPantheonController implements PantheonController { final KeyPair nodeKeys, final Path dataDirectory, final MetricsSystem metricsSystem, - final Clock clock) { + final Clock clock, + final int maxPendingTransactions) { final ProtocolSchedule protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); @@ -196,7 +197,7 @@ public class IbftPantheonController implements PantheonController { final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( - protocolSchedule, protocolContext, ethContext, clock); + protocolSchedule, protocolContext, ethContext, clock, maxPendingTransactions); final IbftEventQueue ibftEventQueue = new IbftEventQueue(ibftConfig.getMessageQueueLimit()); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index 2b6658f7d5..240948a46d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -104,7 +104,8 @@ public class MainnetPantheonController implements PantheonController { final PrivacyParameters privacyParameters, final Path dataDirectory, final MetricsSystem metricsSystem, - final Clock clock) { + final Clock clock, + final int maxPendingTransactions) { final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final ProtocolContext protocolContext = @@ -148,7 +149,11 @@ public class MainnetPantheonController implements PantheonController { final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( - protocolSchedule, protocolContext, ethProtocolManager.ethContext(), clock); + protocolSchedule, + protocolContext, + ethProtocolManager.ethContext(), + clock, + maxPendingTransactions); final ExecutorService minerThreadPool = Executors.newCachedThreadPool(); final EthHashMinerExecutor executor = diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java index abc6a8d29e..55f09f876a 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java @@ -52,7 +52,8 @@ public interface PantheonController extends Closeable { final MetricsSystem metricsSystem, final PrivacyParameters privacyParameters, final Path dataDirectory, - final Clock clock) { + final Clock clock, + final int maxPendingTransactions) { final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); @@ -68,7 +69,8 @@ public interface PantheonController extends Closeable { privacyParameters, dataDirectory, metricsSystem, - clock); + clock, + maxPendingTransactions); } else if (configOptions.isIbft2()) { return IbftPantheonController.init( storageProvider, @@ -79,7 +81,8 @@ public interface PantheonController extends Closeable { nodeKeys, dataDirectory, metricsSystem, - clock); + clock, + maxPendingTransactions); } else if (configOptions.isIbftLegacy()) { return IbftLegacyPantheonController.init( storageProvider, @@ -89,7 +92,8 @@ public interface PantheonController extends Closeable { nodeKeys, dataDirectory, metricsSystem, - clock); + clock, + maxPendingTransactions); } else if (configOptions.isClique()) { return CliquePantheonController.init( storageProvider, @@ -100,7 +104,8 @@ public interface PantheonController extends Closeable { nodeKeys, dataDirectory, metricsSystem, - clock); + clock, + maxPendingTransactions); } else { throw new IllegalArgumentException("Unknown consensus mechanism defined"); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java index 80f54dc340..b1b5353351 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.crypto.SECP256K1; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.mainnet.PrecompiledContract; @@ -58,7 +59,8 @@ public class PrivacyTest { new NoOpMetricsSystem(), privacyParameters, dataDir, - TestClock.fixed()); + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); Address privacyContractAddress = Address.privacyPrecompiled(ADDRESS); PrecompiledContract precompiledContract = diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index f63719bbf5..e351f61be4 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -28,6 +28,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockImporter; import tech.pegasys.pantheon.ethereum.core.BlockSyncTestUtils; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; @@ -111,7 +112,8 @@ public final class RunnerTest { PrivacyParameters.noPrivacy(), dataDirAhead, noOpMetricsSystem, - TestClock.fixed())) { + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS)) { setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); } @@ -128,7 +130,8 @@ public final class RunnerTest { PrivacyParameters.noPrivacy(), dataDirAhead, noOpMetricsSystem, - TestClock.fixed()); + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration(); final WebSocketConfiguration aheadWebSocketConfiguration = wsRpcConfiguration(); @@ -184,7 +187,8 @@ public final class RunnerTest { PrivacyParameters.noPrivacy(), dataDirBehind, noOpMetricsSystem, - TestClock.fixed()); + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); final Peer advertisedPeer = runnerAhead.getAdvertisedPeer().get(); final EthNetworkConfig behindEthNetworkConfiguration = new EthNetworkConfig( diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java index 062d8baa80..3ab957c85d 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -103,6 +103,7 @@ public abstract class CommandTestAbstract { when(mockControllerBuilder.ethNetworkConfig(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.miningParameters(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.devMode(anyBoolean())).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.maxPendingTransactions(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.nodePrivateKeyFile(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.metricsSystem(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.privacyParameters(any())).thenReturn(mockControllerBuilder); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java index 870039e9de..ebf2febde5 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -37,6 +37,7 @@ import tech.pegasys.pantheon.PantheonInfo; import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.MiningParameters; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; @@ -444,6 +445,8 @@ public class PantheonCommandTest extends CommandTestAbstract { verify(mockRunnerBuilder).build(); verify(mockControllerBuilder).devMode(eq(false)); + verify(mockControllerBuilder) + .maxPendingTransactions(eq(PendingTransactions.MAX_PENDING_TRANSACTIONS)); verify(mockControllerBuilder).build(); // TODO: Re-enable as per NC-1057/NC-1681 diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java index 1f8e5f5a17..a84551b09e 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java @@ -20,6 +20,7 @@ import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; +import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; @@ -60,7 +61,8 @@ public final class BlockImporterTest { new NoOpMetricsSystem(), PrivacyParameters.noPrivacy(), dataDir, - TestClock.fixed()); + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, targetController); // Don't count the Genesis block @@ -96,7 +98,8 @@ public final class BlockImporterTest { new NoOpMetricsSystem(), PrivacyParameters.noPrivacy(), dataDir, - TestClock.fixed()); + TestClock.fixed(), + PendingTransactions.MAX_PENDING_TRANSACTIONS); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, controller); // Don't count the Genesis block diff --git a/pantheon/src/test/resources/everything_config.toml b/pantheon/src/test/resources/everything_config.toml index 83f054cebf..142c3b025e 100644 --- a/pantheon/src/test/resources/everything_config.toml +++ b/pantheon/src/test/resources/everything_config.toml @@ -79,4 +79,6 @@ permissions-config-file="./permissions_config.toml" privacy-url="http://127.0.0.1:8888" privacy-public-key-file="./pubKey.pub" privacy-enabled=false -privacy-precompiled-address=9 \ No newline at end of file +privacy-precompiled-address=9 + +tx-pool-max-size=1234