From e60efe82a9925ec3793273b262cc680609105f40 Mon Sep 17 00:00:00 2001 From: cfelde Date: Mon, 9 Sep 2019 17:19:17 +0100 Subject: [PATCH 1/2] [PAN-3023] Add command line option for target gas limit --- .../dsl/node/ThreadPantheonNodeRunner.java | 1 + .../blockcreation/CliqueMinerExecutor.java | 8 ++-- .../CliqueMinerExecutorTest.java | 9 +++-- .../blockcreation/AbstractMinerExecutor.java | 6 ++- .../blockcreation/EthHashMinerExecutor.java | 8 ++-- .../EthHashMinerExecutorTest.java | 6 ++- .../pegasys/pantheon/cli/PantheonCommand.java | 37 +++++++++++++++++- .../CliquePantheonControllerBuilder.java | 3 +- .../IbftPantheonControllerBuilder.java | 2 +- .../MainnetPantheonControllerBuilder.java | 3 +- .../controller/PantheonControllerBuilder.java | 9 +++++ .../tech/pegasys/pantheon/PrivacyTest.java | 1 + .../tech/pegasys/pantheon/RunnerTest.java | 3 ++ .../chainexport/RlpBlockExporterTest.java | 1 + .../chainimport/JsonBlockImporterTest.java | 1 + .../chainimport/RlpBlockImporterTest.java | 2 + .../pantheon/cli/CommandTestAbstract.java | 1 + .../pantheon/cli/PantheonCommandTest.java | 38 +++++++++++++++++++ .../src/test/resources/everything_config.toml | 5 ++- 19 files changed, 127 insertions(+), 17 deletions(-) diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java index 19f530ee09..3d533b57ec 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java @@ -119,6 +119,7 @@ public void startNode(final PantheonNode node) { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .clock(Clock.systemUTC()) .isRevertReasonEnabled(node.isRevertReasonEnabled()) + .gasLimitCalculator((gasLimit) -> gasLimit) .build(); } catch (final IOException e) { throw new RuntimeException("Error building PantheonController", e); diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java index 96514f3c24..6ad75b14cc 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -53,14 +53,16 @@ public CliqueMinerExecutor( final KeyPair nodeKeys, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, - final EpochManager epochManager) { + final EpochManager epochManager, + final Function gasLimitCalculator) { super( protocolContext, executorService, protocolSchedule, pendingTransactions, miningParams, - blockScheduler); + blockScheduler, + gasLimitCalculator); this.nodeKeys = nodeKeys; this.localAddress = Util.publicKeyToAddress(nodeKeys.getPublicKey()); this.epochManager = epochManager; @@ -89,7 +91,7 @@ private CliqueBlockMiner createMiner( pendingTransactions, protocolContext, protocolSchedule, - (gasLimit) -> gasLimit, + gasLimitCalculator, nodeKeys, minTransactionGasPrice, header, diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index ab917aabc5..f4fadb6b17 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -98,7 +98,8 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { proposerKeyPair, new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, vanityData, false), mock(CliqueBlockScheduler.class), - new EpochManager(EPOCH_LENGTH)); + new EpochManager(EPOCH_LENGTH), + (gasLimit) -> gasLimit); // NOTE: Passing in the *parent* block, so must be 1 less than EPOCH final BlockHeader header = blockHeaderBuilder.number(EPOCH_LENGTH - 1).buildHeader(); @@ -135,7 +136,8 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() { proposerKeyPair, new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, vanityData, false), mock(CliqueBlockScheduler.class), - new EpochManager(EPOCH_LENGTH)); + new EpochManager(EPOCH_LENGTH), + (gasLimit) -> gasLimit); // Parent block was epoch, so the next block should contain no validators. final BlockHeader header = blockHeaderBuilder.number(EPOCH_LENGTH).buildHeader(); @@ -172,7 +174,8 @@ public void shouldUseLatestVanityData() { proposerKeyPair, new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, initialVanityData, false), mock(CliqueBlockScheduler.class), - new EpochManager(EPOCH_LENGTH)); + new EpochManager(EPOCH_LENGTH), + (gasLimit) -> gasLimit); executor.setExtraData(modifiedVanityData); final BytesValue extraDataBytes = executor.calculateExtraData(blockHeaderBuilder.buildHeader()); diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMinerExecutor.java index f92b660481..9f1dc57443 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMinerExecutor.java @@ -25,6 +25,7 @@ import java.util.Optional; import java.util.concurrent.ExecutorService; +import java.util.function.Function; public abstract class AbstractMinerExecutor< C, M extends BlockMiner>> { @@ -34,6 +35,7 @@ public abstract class AbstractMinerExecutor< protected final ProtocolSchedule protocolSchedule; protected final PendingTransactions pendingTransactions; protected final AbstractBlockScheduler blockScheduler; + protected final Function gasLimitCalculator; protected volatile BytesValue extraData; protected volatile Wei minTransactionGasPrice; @@ -44,7 +46,8 @@ public AbstractMinerExecutor( final ProtocolSchedule protocolSchedule, final PendingTransactions pendingTransactions, final MiningParameters miningParams, - final AbstractBlockScheduler blockScheduler) { + final AbstractBlockScheduler blockScheduler, + final Function gasLimitCalculator) { this.protocolContext = protocolContext; this.executorService = executorService; this.protocolSchedule = protocolSchedule; @@ -52,6 +55,7 @@ public AbstractMinerExecutor( this.extraData = miningParams.getExtraData(); this.minTransactionGasPrice = miningParams.getMinTransactionGasPrice(); this.blockScheduler = blockScheduler; + this.gasLimitCalculator = gasLimitCalculator; } public abstract M startAsyncMining( diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutor.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutor.java index 6041890cf8..f79ad268b6 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutor.java @@ -37,14 +37,16 @@ public EthHashMinerExecutor( final ProtocolSchedule protocolSchedule, final PendingTransactions pendingTransactions, final MiningParameters miningParams, - final AbstractBlockScheduler blockScheduler) { + final AbstractBlockScheduler blockScheduler, + final Function gasLimitCalculator) { super( protocolContext, executorService, protocolSchedule, pendingTransactions, miningParams, - blockScheduler); + blockScheduler, + gasLimitCalculator); this.coinbase = miningParams.getCoinbase(); } @@ -77,7 +79,7 @@ private EthHashBlockMiner createMiner( pendingTransactions, protocolContext, protocolSchedule, - (gasLimit) -> gasLimit, + gasLimitCalculator, solver, minTransactionGasPrice, parentHeader); diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java index a67f42e5db..95b4f63a1d 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java @@ -49,7 +49,8 @@ public void startingMiningWithoutCoinbaseThrowsException() { null, pendingTransactions, miningParameters, - new DefaultBlockScheduler(1, 10, TestClock.fixed())); + new DefaultBlockScheduler(1, 10, TestClock.fixed()), + (gasLimit) -> gasLimit); assertThatExceptionOfType(CoinbaseNotSetException.class) .isThrownBy(() -> executor.startAsyncMining(Subscribers.create(), null)) @@ -74,7 +75,8 @@ public void settingCoinbaseToNullThrowsException() { null, pendingTransactions, miningParameters, - new DefaultBlockScheduler(1, 10, TestClock.fixed())); + new DefaultBlockScheduler(1, 10, TestClock.fixed()), + (gasLimit) -> gasLimit); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> executor.setCoinbase(null)) 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 12f107054d..8879e9a175 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -118,6 +118,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -633,6 +634,12 @@ void setBannedNodeIds(final List values) { "The name of a file containing the private key used to sign privacy marker transactions. If unset, each will be signed with a random key.") private final Path privacyMarkerTransactionSigningKeyPath = null; + @Option( + names = {"--target-gas-limit"}, + description = + "Sets target gas limit per block. If set each blocks gas limit will approach this setting over time if the current gas limit is different.") + private final Long targetGasLimit = null; + @Option( names = {"--tx-pool-max-size"}, paramLabel = MANDATORY_INTEGER_FORMAT_HELP, @@ -657,6 +664,7 @@ void setBannedNodeIds(final List values) { private MetricsConfiguration metricsConfiguration; private Optional permissioningConfiguration; private Collection staticNodes; + private Function gasLimitCalculator; private PantheonController pantheonController; private final Supplier metricsSystem = @@ -879,6 +887,7 @@ private PantheonCommand configure() throws Exception { webSocketConfiguration = webSocketConfiguration(); permissioningConfiguration = permissioningConfiguration(); staticNodes = loadStaticNodes(); + gasLimitCalculator = gasLimitCalculator(); logger.info("Connecting to {} static nodes.", staticNodes.size()); logger.trace("Static Nodes = {}", staticNodes); final List enodeURIs = @@ -946,7 +955,8 @@ public PantheonControllerBuilder getControllerBuilder() { .clock(Clock.systemUTC()) .isRevertReasonEnabled(isRevertReasonEnabled) .isPruningEnabled(isPruningEnabled) - .pruningConfiguration(buildPruningConfiguration()); + .pruningConfiguration(buildPruningConfiguration()) + .gasLimitCalculator(gasLimitCalculator); } catch (final IOException e) { throw new ExecutionException(this.commandLine, "Invalid path", e); } @@ -1536,6 +1546,31 @@ private Set loadStaticNodes() throws IOException { return StaticNodesParser.fromPath(staticNodesPath); } + private Function gasLimitCalculator() { + final long targetGasLimit = this.targetGasLimit == null ? 0L : this.targetGasLimit; + final long adjustmentFactor = 1024L; + + if (targetGasLimit > 0L) { + return (gasLimit) -> { + long newGasLimit; + + if (targetGasLimit > gasLimit) { + newGasLimit = Math.min(targetGasLimit, gasLimit + adjustmentFactor); + } else if (targetGasLimit < gasLimit) { + newGasLimit = Math.max(targetGasLimit, gasLimit - adjustmentFactor); + } else { + return gasLimit; + } + + logger.debug("Adjusting block gas limit from {} to {}", gasLimit, newGasLimit); + + return newGasLimit; + }; + } else { + return gasLimit -> gasLimit; + } + } + public PantheonExceptionHandler exceptionHandler() { return new PantheonExceptionHandler(this::getLogLevel); } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java index 269b5e8427..8f4222ba6d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java @@ -94,7 +94,8 @@ protected MiningCoordinator createMiningCoordinator( protocolContext.getConsensusState().getVoteTallyCache(), localAddress, secondsBetweenBlocks), - epochManager); + epochManager, + gasLimitCalculator); final CliqueMiningCoordinator miningCoordinator = new CliqueMiningCoordinator( protocolContext.getBlockchain(), diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java index e985947e52..3b3dbaecae 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java @@ -111,7 +111,7 @@ protected MiningCoordinator createMiningCoordinator( final IbftBlockCreatorFactory blockCreatorFactory = new IbftBlockCreatorFactory( - (gasLimit) -> gasLimit, + gasLimitCalculator, transactionPool.getPendingTransactions(), protocolContext, protocolSchedule, diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java index a77f17d5d5..cd170ae066 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java @@ -56,7 +56,8 @@ protected MiningCoordinator createMiningCoordinator( new DefaultBlockScheduler( MainnetBlockHeaderValidator.MINIMUM_SECONDS_SINCE_PARENT, MainnetBlockHeaderValidator.TIMESTAMP_TOLERANCE_S, - clock)); + clock), + gasLimitCalculator); final EthHashMiningCoordinator miningCoordinator = new EthHashMiningCoordinator(protocolContext.getBlockchain(), executor, syncState); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java index 6c4c2407ea..60059dde6f 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java @@ -63,6 +63,7 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.concurrent.Executors; +import java.util.function.Function; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.logging.log4j.LogManager; @@ -84,6 +85,7 @@ public abstract class PantheonControllerBuilder { protected Clock clock; protected KeyPair nodeKeys; protected boolean isRevertReasonEnabled; + protected Function gasLimitCalculator; private StorageProvider storageProvider; private final List shutdownActions = new ArrayList<>(); private RocksDbConfiguration rocksDbConfiguration; @@ -181,6 +183,12 @@ public PantheonControllerBuilder pruningConfiguration( return this; } + public PantheonControllerBuilder gasLimitCalculator( + final Function gasLimitCalculator) { + this.gasLimitCalculator = gasLimitCalculator; + return this; + } + public PantheonController build() throws IOException { checkNotNull(genesisConfig, "Missing genesis config"); checkNotNull(syncConfig, "Missing sync config"); @@ -193,6 +201,7 @@ public PantheonController build() throws IOException { checkNotNull(clock, "Mising clock"); checkNotNull(transactionPoolConfiguration, "Missing transaction pool configuration"); checkNotNull(nodeKeys, "Missing node keys"); + checkNotNull(gasLimitCalculator, "Missing gas limit calculator"); checkArgument( storageProvider != null || rocksDbConfiguration != null, "Must supply either a storage provider or RocksDB configuration"); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java index 772ed6fb5e..575af4b7d4 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java @@ -66,6 +66,7 @@ public void privacyPrecompiled() throws IOException { .clock(TestClock.fixed()) .privacyParameters(privacyParameters) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); final Address privacyContractAddress = Address.privacyPrecompiled(ADDRESS); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index baf0d39bc6..464df84254 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -135,6 +135,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) .storageProvider(createKeyValueStorageProvider(dbAhead)) + .gasLimitCalculator(gasLimit -> gasLimit) .build()) { setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); } @@ -154,6 +155,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) .storageProvider(createKeyValueStorageProvider(dbAhead)) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration(); @@ -212,6 +214,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .privacyParameters(PrivacyParameters.DEFAULT) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); final EnodeURL enode = runnerAhead.getLocalEnode().get(); final EthNetworkConfig behindEthNetworkConfiguration = diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java index da226eeb86..2454cb801c 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java @@ -88,6 +88,7 @@ private static PantheonController createController() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java index ff286a749e..295a615dd5 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java @@ -425,6 +425,7 @@ protected PantheonController createController(final GenesisConfigFile genesis .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); } } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java index 9c4f31dc4a..476275e37c 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java @@ -66,6 +66,7 @@ public void blockImport() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); final RlpBlockImporter.ImportResult result = rlpBlockImporter.importBlockchain(source, targetController); @@ -105,6 +106,7 @@ public void ibftImport() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) + .gasLimitCalculator(gasLimit -> gasLimit) .build(); final RlpBlockImporter.ImportResult result = rlpBlockImporter.importBlockchain(source, controller); 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 6bb661749c..e1134d4032 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -154,6 +154,7 @@ public void initMocks() throws Exception { when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder); when(mockControllerBuilder.isPruningEnabled(anyBoolean())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.pruningConfiguration(any())).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder); // doReturn used because of generic PantheonController doReturn(mockController).when(mockControllerBuilder).build(); 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 d0f0bb24be..2ecfa72b80 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -71,6 +71,7 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -175,6 +176,7 @@ public void callingPantheonCommandWithoutOptionsMustSyncWithDefaultValues() thro verify(mockControllerBuilder).dataDirectory(isNotNull()); verify(mockControllerBuilder).miningParameters(miningArg.capture()); verify(mockControllerBuilder).nodePrivateKeyFile(isNotNull()); + verify(mockControllerBuilder).gasLimitCalculator(isNotNull()); verify(mockControllerBuilder).build(); assertThat(syncConfigurationCaptor.getValue().getSyncMode()).isEqualTo(SyncMode.FULL); @@ -2735,4 +2737,40 @@ public void tomlThatHasInvalidOptions() throws IOException { assertThat(commandErrorOutput.toString()) .contains("Unknown options in TOML configuration file: invalid_option, invalid_option2"); } + + @Test + public void targetGasLimitIsEnabledWhenSpecified() throws Exception { + parseCommand("--target-gas-limit=10000000"); + + @SuppressWarnings("unchecked") + final ArgumentCaptor> gasLimitCalculatorArg = + ArgumentCaptor.forClass((Class) Function.class); + + verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArg.capture()); + verify(mockControllerBuilder).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + + assertThat(gasLimitCalculatorArg.getValue().apply(9000000L)).isEqualTo(9000000L + 1024L); + assertThat(gasLimitCalculatorArg.getValue().apply(11000000L)).isEqualTo(11000000L - 1024L); + } + + @Test + public void targetGasLimitIsDisabledWhenNotSpecified() throws Exception { + parseCommand(); + + @SuppressWarnings("unchecked") + final ArgumentCaptor> gasLimitCalculatorArg = + ArgumentCaptor.forClass((Class) Function.class); + + verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArg.capture()); + verify(mockControllerBuilder).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + + assertThat(gasLimitCalculatorArg.getValue().apply(9000000L)).isEqualTo(9000000L); + assertThat(gasLimitCalculatorArg.getValue().apply(11000000L)).isEqualTo(11000000L); + } } diff --git a/pantheon/src/test/resources/everything_config.toml b/pantheon/src/test/resources/everything_config.toml index 0c724491dd..c8d4d9854f 100644 --- a/pantheon/src/test/resources/everything_config.toml +++ b/pantheon/src/test/resources/everything_config.toml @@ -104,4 +104,7 @@ tx-pool-max-size=1234 Xincoming-tx-messages-keep-alive-seconds=60 # Revert Reason -revert-reason-enabled=false \ No newline at end of file +revert-reason-enabled=false + +# Gas limit +target-gas-limit=8000000 \ No newline at end of file From 453d65f5a15dbb405edab09886cebf9545d4088d Mon Sep 17 00:00:00 2001 From: cfelde Date: Fri, 13 Sep 2019 11:38:58 +0100 Subject: [PATCH 2/2] [PAN-3023] Add command line option for target gas limit --- .../dsl/node/ThreadPantheonNodeRunner.java | 3 +- .../blockcreation/CliqueBlockCreatorTest.java | 9 ++-- .../CliqueMinerExecutorTest.java | 7 +-- .../ibft/support/TestContextBuilder.java | 3 +- .../EthHashMinerExecutorTest.java | 5 +- .../pegasys/pantheon/cli/PantheonCommand.java | 30 +----------- .../controller/GasLimitCalculator.java | 46 +++++++++++++++++++ .../controller/PantheonControllerBuilder.java | 8 ++-- .../tech/pegasys/pantheon/PrivacyTest.java | 3 +- .../tech/pegasys/pantheon/RunnerTest.java | 7 +-- .../chainexport/RlpBlockExporterTest.java | 3 +- .../chainimport/JsonBlockImporterTest.java | 3 +- .../chainimport/RlpBlockImporterTest.java | 5 +- .../pantheon/cli/CommandTestAbstract.java | 2 +- .../pantheon/cli/PantheonCommandTest.java | 22 ++++----- .../controller/GasLimitCalculatorTest.java | 44 ++++++++++++++++++ 16 files changed, 132 insertions(+), 68 deletions(-) create mode 100644 pantheon/src/main/java/tech/pegasys/pantheon/controller/GasLimitCalculator.java create mode 100644 pantheon/src/test/java/tech/pegasys/pantheon/controller/GasLimitCalculatorTest.java diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java index 6b5c2b27f5..81c9f57fff 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.Runner; import tech.pegasys.pantheon.RunnerBuilder; import tech.pegasys.pantheon.cli.config.EthNetworkConfig; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.KeyPairUtil; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.controller.PantheonControllerBuilder; @@ -142,7 +143,7 @@ public void startNode(final PantheonNode node) { .clock(Clock.systemUTC()) .isRevertReasonEnabled(node.isRevertReasonEnabled()) .storageProvider(storageProvider) - .gasLimitCalculator((gasLimit) -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); } catch (final IOException e) { throw new RuntimeException("Error building PantheonController", e); diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 3ed775bee8..bc1d3701fe 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -51,6 +51,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; +import java.util.function.Function; import com.google.common.collect.Lists; import org.junit.Before; @@ -121,7 +122,7 @@ public void proposerAddressCanBeExtractFromAConstructedBlock() { metricsSystem), protocolContext, protocolSchedule, - gasLimit -> gasLimit, + Function.identity(), proposerKeyPair, Wei.ZERO, blockchain.getChainHeadHeader(), @@ -152,7 +153,7 @@ public void insertsValidVoteIntoConstructedBlock() { metricsSystem), protocolContext, protocolSchedule, - gasLimit -> gasLimit, + Function.identity(), proposerKeyPair, Wei.ZERO, blockchain.getChainHeadHeader(), @@ -182,7 +183,7 @@ public void insertsNoVoteWhenAuthInValidators() { metricsSystem), protocolContext, protocolSchedule, - gasLimit -> gasLimit, + Function.identity(), proposerKeyPair, Wei.ZERO, blockchain.getChainHeadHeader(), @@ -215,7 +216,7 @@ public void insertsNoVoteWhenAtEpoch() { metricsSystem), protocolContext, protocolSchedule, - gasLimit -> gasLimit, + Function.identity(), proposerKeyPair, Wei.ZERO, blockchain.getChainHeadHeader(), diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index f4fadb6b17..d2832834da 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -46,6 +46,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.Executors; +import java.util.function.Function; import com.google.common.collect.Lists; import org.junit.Before; @@ -99,7 +100,7 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, vanityData, false), mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH), - (gasLimit) -> gasLimit); + Function.identity()); // NOTE: Passing in the *parent* block, so must be 1 less than EPOCH final BlockHeader header = blockHeaderBuilder.number(EPOCH_LENGTH - 1).buildHeader(); @@ -137,7 +138,7 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() { new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, vanityData, false), mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH), - (gasLimit) -> gasLimit); + Function.identity()); // Parent block was epoch, so the next block should contain no validators. final BlockHeader header = blockHeaderBuilder.number(EPOCH_LENGTH).buildHeader(); @@ -175,7 +176,7 @@ public void shouldUseLatestVanityData() { new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, initialVanityData, false), mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH), - (gasLimit) -> gasLimit); + Function.identity()); executor.setExtraData(modifiedVanityData); final BytesValue extraDataBytes = executor.calculateExtraData(blockHeaderBuilder.buildHeader()); diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java index 655982a4a1..78ffed274f 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java @@ -81,6 +81,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Executors; +import java.util.function.Function; import java.util.stream.Collectors; import com.google.common.collect.Iterables; @@ -290,7 +291,7 @@ private static ControllerAndState createControllerAndFinalState( final IbftBlockCreatorFactory blockCreatorFactory = new IbftBlockCreatorFactory( - (gasLimit) -> gasLimit, + Function.identity(), pendingTransactions, // changed from IbftPantheonController protocolContext, protocolSchedule, diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java index 95b4f63a1d..c7001df951 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java @@ -24,6 +24,7 @@ import tech.pegasys.pantheon.util.Subscribers; import java.util.concurrent.Executors; +import java.util.function.Function; import org.junit.Test; @@ -50,7 +51,7 @@ public void startingMiningWithoutCoinbaseThrowsException() { pendingTransactions, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - (gasLimit) -> gasLimit); + Function.identity()); assertThatExceptionOfType(CoinbaseNotSetException.class) .isThrownBy(() -> executor.startAsyncMining(Subscribers.create(), null)) @@ -76,7 +77,7 @@ public void settingCoinbaseToNullThrowsException() { pendingTransactions, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - (gasLimit) -> gasLimit); + Function.identity()); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> executor.setCoinbase(null)) 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 f5a1b8dc05..6a577c9146 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -123,7 +123,6 @@ import java.util.Optional; import java.util.Set; import java.util.TreeMap; -import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -687,7 +686,6 @@ void setBannedNodeIds(final List values) { private MetricsConfiguration metricsConfiguration; private Optional permissioningConfiguration; private Collection staticNodes; - private Function gasLimitCalculator; private PantheonController pantheonController; private StandaloneCommand standaloneCommands; private PantheonConfiguration pluginCommonConfiguration; @@ -945,7 +943,6 @@ private PantheonCommand configure() throws Exception { webSocketConfiguration = webSocketConfiguration(); permissioningConfiguration = permissioningConfiguration(); staticNodes = loadStaticNodes(); - gasLimitCalculator = gasLimitCalculator(); logger.info("Connecting to {} static nodes.", staticNodes.size()); logger.trace("Static Nodes = {}", staticNodes); final List enodeURIs = @@ -1013,7 +1010,7 @@ public PantheonControllerBuilder getControllerBuilder() { .isPruningEnabled(isPruningEnabled) .pruningConfiguration(buildPruningConfiguration()) .genesisConfigOverrides(genesisConfigOverrides) - .gasLimitCalculator(gasLimitCalculator); + .targetGasLimit(targetGasLimit); } catch (final IOException e) { throw new ExecutionException(this.commandLine, "Invalid path", e); } @@ -1608,31 +1605,6 @@ private Set loadStaticNodes() throws IOException { return StaticNodesParser.fromPath(staticNodesPath); } - private Function gasLimitCalculator() { - final long targetGasLimit = this.targetGasLimit == null ? 0L : this.targetGasLimit; - final long adjustmentFactor = 1024L; - - if (targetGasLimit > 0L) { - return (gasLimit) -> { - long newGasLimit; - - if (targetGasLimit > gasLimit) { - newGasLimit = Math.min(targetGasLimit, gasLimit + adjustmentFactor); - } else if (targetGasLimit < gasLimit) { - newGasLimit = Math.max(targetGasLimit, gasLimit - adjustmentFactor); - } else { - return gasLimit; - } - - logger.debug("Adjusting block gas limit from {} to {}", gasLimit, newGasLimit); - - return newGasLimit; - }; - } else { - return gasLimit -> gasLimit; - } - } - public PantheonExceptionHandler exceptionHandler() { return new PantheonExceptionHandler(this::getLogLevel); } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/GasLimitCalculator.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/GasLimitCalculator.java new file mode 100644 index 0000000000..c71102b2ac --- /dev/null +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/GasLimitCalculator.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * 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. + */ +package tech.pegasys.pantheon.controller; + +import java.util.function.Function; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class GasLimitCalculator implements Function { + private static final Logger LOG = LogManager.getLogger(); + public static final long ADJUSTMENT_FACTOR = 1024L; + public static final Long DEFAULT = null; + private final long targetGasLimit; + + public GasLimitCalculator(final Long targetGasLimit) { + this.targetGasLimit = targetGasLimit == null ? 0L : targetGasLimit; + } + + @Override + public Long apply(final Long gasLimit) { + long newGasLimit; + + if (targetGasLimit > gasLimit) { + newGasLimit = Math.min(targetGasLimit, gasLimit + ADJUSTMENT_FACTOR); + } else if (targetGasLimit < gasLimit) { + newGasLimit = Math.max(targetGasLimit, gasLimit - ADJUSTMENT_FACTOR); + } else { + return gasLimit; + } + + LOG.debug("Adjusting block gas limit from {} to {}", gasLimit, newGasLimit); + + return newGasLimit; + } +} diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java index 0c76cb534f..5ef6636347 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java @@ -61,7 +61,6 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.concurrent.Executors; -import java.util.function.Function; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.logging.log4j.LogManager; @@ -84,7 +83,7 @@ public abstract class PantheonControllerBuilder { protected Clock clock; protected KeyPair nodeKeys; protected boolean isRevertReasonEnabled; - protected Function gasLimitCalculator; + protected GasLimitCalculator gasLimitCalculator; private StorageProvider storageProvider; private final List shutdownActions = new ArrayList<>(); private boolean isPruningEnabled; @@ -182,9 +181,8 @@ public PantheonControllerBuilder genesisConfigOverrides( return this; } - public PantheonControllerBuilder gasLimitCalculator( - final Function gasLimitCalculator) { - this.gasLimitCalculator = gasLimitCalculator; + public PantheonControllerBuilder targetGasLimit(final Long targetGasLimit) { + this.gasLimitCalculator = new GasLimitCalculator(targetGasLimit); return this; } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java index 497205016a..d5503a7873 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java @@ -15,6 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.Account; @@ -77,7 +78,7 @@ public void privacyPrecompiled() throws IOException { .clock(TestClock.fixed()) .privacyParameters(privacyParameters) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); final Address privacyContractAddress = Address.privacyPrecompiled(ADDRESS); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index abce83f9ad..f5610fbf40 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -20,6 +20,7 @@ import tech.pegasys.pantheon.cli.config.EthNetworkConfig; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.MainnetPantheonControllerBuilder; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; @@ -143,7 +144,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) .storageProvider(createKeyValueStorageProvider(dbAhead)) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build()) { setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); } @@ -163,7 +164,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) .storageProvider(createKeyValueStorageProvider(dbAhead)) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration(); @@ -222,7 +223,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .privacyParameters(PrivacyParameters.DEFAULT) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); final EnodeURL enode = runnerAhead.getLocalEnode().get(); final EthNetworkConfig behindEthNetworkConfiguration = diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java index 2454cb801c..70416835d7 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainexport/RlpBlockExporterTest.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.chainimport.RlpBlockImporter; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.chain.Blockchain; @@ -88,7 +89,7 @@ private static PantheonController createController() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java index 295a615dd5..1cb9a29971 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/JsonBlockImporterTest.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.JsonUtil; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.chain.Blockchain; @@ -425,7 +426,7 @@ protected PantheonController createController(final GenesisConfigFile genesis .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); } } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java index 476275e37c..1ecec4afa5 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/chainimport/RlpBlockImporterTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.controller.GasLimitCalculator; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; @@ -66,7 +67,7 @@ public void blockImport() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); final RlpBlockImporter.ImportResult result = rlpBlockImporter.importBlockchain(source, targetController); @@ -106,7 +107,7 @@ public void ibftImport() throws IOException { .dataDirectory(dataDir) .clock(TestClock.fixed()) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) - .gasLimitCalculator(gasLimit -> gasLimit) + .targetGasLimit(GasLimitCalculator.DEFAULT) .build(); final RlpBlockImporter.ImportResult result = rlpBlockImporter.importBlockchain(source, controller); 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 bf5fd279c6..5d6abe28eb 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -164,7 +164,7 @@ public void initMocks() throws Exception { when(mockControllerBuilder.isPruningEnabled(anyBoolean())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.pruningConfiguration(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.genesisConfigOverrides(any())).thenReturn(mockControllerBuilder); - when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.targetGasLimit(any())).thenReturn(mockControllerBuilder); // doReturn used because of generic PantheonController doReturn(mockController).when(mockControllerBuilder).build(); 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 daa3678df5..ebcc1e2f3d 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -19,6 +19,7 @@ import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -72,7 +73,6 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -174,7 +174,7 @@ public void callingPantheonCommandWithoutOptionsMustSyncWithDefaultValues() thro verify(mockControllerBuilder).miningParameters(miningArg.capture()); verify(mockControllerBuilder).nodePrivateKeyFile(isNotNull()); verify(mockControllerBuilder).storageProvider(storageProviderArgumentCaptor.capture()); - verify(mockControllerBuilder).gasLimitCalculator(isNotNull()); + verify(mockControllerBuilder).targetGasLimit(isNull()); verify(mockControllerBuilder).build(); assertThat(storageProviderArgumentCaptor.getValue()).isNotNull(); @@ -2742,35 +2742,29 @@ public void tomlThatHasInvalidOptions() throws IOException { public void targetGasLimitIsEnabledWhenSpecified() throws Exception { parseCommand("--target-gas-limit=10000000"); - @SuppressWarnings("unchecked") - final ArgumentCaptor> gasLimitCalculatorArg = - ArgumentCaptor.forClass((Class) Function.class); + final ArgumentCaptor targetGasLimitArg = ArgumentCaptor.forClass(Long.class); - verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArg.capture()); + verify(mockControllerBuilder).targetGasLimit(targetGasLimitArg.capture()); verify(mockControllerBuilder).build(); assertThat(commandOutput.toString()).isEmpty(); assertThat(commandErrorOutput.toString()).isEmpty(); - assertThat(gasLimitCalculatorArg.getValue().apply(9000000L)).isEqualTo(9000000L + 1024L); - assertThat(gasLimitCalculatorArg.getValue().apply(11000000L)).isEqualTo(11000000L - 1024L); + assertThat(targetGasLimitArg.getValue()).isEqualTo(10_000_000L); } @Test public void targetGasLimitIsDisabledWhenNotSpecified() throws Exception { parseCommand(); - @SuppressWarnings("unchecked") - final ArgumentCaptor> gasLimitCalculatorArg = - ArgumentCaptor.forClass((Class) Function.class); + final ArgumentCaptor targetGasLimitArg = ArgumentCaptor.forClass(Long.class); - verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArg.capture()); + verify(mockControllerBuilder).targetGasLimit(targetGasLimitArg.capture()); verify(mockControllerBuilder).build(); assertThat(commandOutput.toString()).isEmpty(); assertThat(commandErrorOutput.toString()).isEmpty(); - assertThat(gasLimitCalculatorArg.getValue().apply(9000000L)).isEqualTo(9000000L); - assertThat(gasLimitCalculatorArg.getValue().apply(11000000L)).isEqualTo(11000000L); + assertThat(targetGasLimitArg.getValue()).isEqualTo(null); } } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/controller/GasLimitCalculatorTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/controller/GasLimitCalculatorTest.java new file mode 100644 index 0000000000..9f3a86227f --- /dev/null +++ b/pantheon/src/test/java/tech/pegasys/pantheon/controller/GasLimitCalculatorTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * 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. + */ +package tech.pegasys.pantheon.controller; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.function.Function; + +import org.junit.Test; + +public class GasLimitCalculatorTest { + @Test + public void verifyGasLimitIsIncreasedWithinLimits() { + Function gasLimitCalculator = new GasLimitCalculator(10_000_000L); + assertThat(gasLimitCalculator.apply(8_000_000L)) + .isEqualTo(8_000_000L + GasLimitCalculator.ADJUSTMENT_FACTOR); + } + + @Test + public void verifyGasLimitIsDecreasedWithinLimits() { + Function gasLimitCalculator = new GasLimitCalculator(10_000_000L); + assertThat(gasLimitCalculator.apply(12_000_000L)) + .isEqualTo(12_000_000L - GasLimitCalculator.ADJUSTMENT_FACTOR); + } + + @Test + public void verifyGasLimitReachesTarget() { + final long target = 10_000_000L; + final long offset = GasLimitCalculator.ADJUSTMENT_FACTOR / 2; + Function gasLimitCalculator = new GasLimitCalculator(target); + assertThat(gasLimitCalculator.apply(target - offset)).isEqualTo(target); + assertThat(gasLimitCalculator.apply(target + offset)).isEqualTo(target); + } +}