diff --git a/CHANGELOG.md b/CHANGELOG.md index 84bb34bb178..2ceaa5b1b50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Transaction call object to accept both `input` and `data` field simultaneously if they are set to equal values [#6702](https://github.com/hyperledger/besu/pull/6702) ### Bug fixes +- Make block transaction selection max time aware of PoA transitions [#6676](https://github.com/hyperledger/besu/pull/6676) ### Download Links diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 679bfc88dd7..6709608834e 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -2149,10 +2149,10 @@ private TransactionPoolConfiguration buildTransactionPoolConfiguration() { private MiningParameters getMiningParameters() { if (miningParameters == null) { - miningOptions.setGenesisBlockPeriodSeconds( - getGenesisBlockPeriodSeconds(getActualGenesisConfigOptions())); miningOptions.setTransactionSelectionService(transactionSelectionServiceImpl); miningParameters = miningOptions.toDomainObject(); + getGenesisBlockPeriodSeconds(getActualGenesisConfigOptions()) + .ifPresent(miningParameters::setBlockPeriodSeconds); initMiningParametersMetrics(miningParameters); } return miningParameters; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java index 976be808495..bcde10077bb 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java @@ -42,7 +42,6 @@ import org.hyperledger.besu.util.number.PositiveNumber; import java.util.List; -import java.util.OptionalInt; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; @@ -191,7 +190,6 @@ static class Unstable { DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; } - private OptionalInt maybeGenesisBlockPeriodSeconds; private TransactionSelectionService transactionSelectionService; private MiningOptions() {} @@ -205,16 +203,6 @@ public static MiningOptions create() { return new MiningOptions(); } - /** - * Set the optional genesis block period per seconds - * - * @param genesisBlockPeriodSeconds if the network is PoA then the block period in seconds - * specified in the genesis file, otherwise empty. - */ - public void setGenesisBlockPeriodSeconds(final OptionalInt genesisBlockPeriodSeconds) { - maybeGenesisBlockPeriodSeconds = genesisBlockPeriodSeconds; - } - /** * Set the transaction selection service * @@ -311,7 +299,6 @@ public void validate( static MiningOptions fromConfig(final MiningParameters miningParameters) { final MiningOptions miningOptions = MiningOptions.create(); - miningOptions.setGenesisBlockPeriodSeconds(miningParameters.getGenesisBlockPeriodSeconds()); miningOptions.setTransactionSelectionService(miningParameters.getTransactionSelectionService()); miningOptions.isMiningEnabled = miningParameters.isMiningEnabled(); miningOptions.iStratumMiningEnabled = miningParameters.isStratumMiningEnabled(); @@ -347,9 +334,6 @@ static MiningOptions fromConfig(final MiningParameters miningParameters) { @Override public MiningParameters toDomainObject() { - checkNotNull( - maybeGenesisBlockPeriodSeconds, - "genesisBlockPeriodSeconds must be set before using this object"); checkNotNull( transactionSelectionService, "transactionSelectionService must be set before using this object"); @@ -370,7 +354,6 @@ public MiningParameters toDomainObject() { } return ImmutableMiningParameters.builder() - .genesisBlockPeriodSeconds(maybeGenesisBlockPeriodSeconds) .transactionSelectionService(transactionSelectionService) .mutableInitValues(updatableInitValuesBuilder.build()) .isStratumMiningEnabled(iStratumMiningEnabled) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index 3fe170983a2..88a675d4f10 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -102,6 +102,18 @@ protected MiningCoordinator createMiningCoordinator( miningExecutor, syncState, new CliqueMiningTracker(localAddress, protocolContext)); + + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + forksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + miningCoordinator.addMinedBlockObserver(ethProtocolManager); // Clique mining is implicitly enabled. diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index d191f034596..eb261ff42ba 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -234,6 +234,17 @@ protected MiningCoordinator createMiningCoordinator( blockchain, bftEventQueue); + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + forksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + if (syncState.isInitialSyncPhaseDone()) { LOG.info("Starting IBFT mining coordinator"); ibftMiningCoordinator.enable(); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 93b0ea55d84..b26088e73f1 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -274,6 +274,17 @@ protected MiningCoordinator createMiningCoordinator( blockchain, bftEventQueue); + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + qbftForksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + if (syncState.isInitialSyncPhaseDone()) { LOG.info("Starting QBFT mining coordinator"); miningCoordinator.enable(); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java index 21d8baf9ee9..1760b957ec6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Consumer; import org.junit.jupiter.api.Test; @@ -113,10 +114,18 @@ protected List getFieldsToIgnore() { protected abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand); protected void internalTestSuccess(final Consumer assertion, final String... args) { + internalTestSuccess((bc, conf) -> conf, assertion, args); + } + + protected void internalTestSuccess( + final BiFunction runtimeConf, + final Consumer assertion, + final String... args) { final TestBesuCommand cmd = parseCommand(args); final T options = getOptionsFromBesuCommand(cmd); - final D config = options.toDomainObject(); + final D config = runtimeConf.apply(cmd, options.toDomainObject()); + assertion.accept(config); assertThat(commandOutput.toString(UTF_8)).isEmpty(); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java index fda642d6ead..55777e16d42 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java @@ -34,7 +34,6 @@ import java.nio.file.Path; import java.time.Duration; import java.util.Optional; -import java.util.OptionalInt; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; @@ -316,6 +315,7 @@ public void posBlockCreationMaxTimeOutOfAllowedRange() { @Test public void blockTxsSelectionMaxTimeDefaultValue() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getNonPoaBlockTxsSelectionMaxTime()) .isEqualTo(DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME)); @@ -324,6 +324,7 @@ public void blockTxsSelectionMaxTimeDefaultValue() { @Test public void blockTxsSelectionMaxTimeOption() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getBlockTxsSelectionMaxTime()).isEqualTo(1700L), "--block-txs-selection-max-time", "1700"); @@ -343,6 +344,7 @@ public void blockTxsSelectionMaxTimeIncompatibleWithPoaNetworks() throws IOExcep @Test public void poaBlockTxsSelectionMaxTimeDefaultValue() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(DEFAULT_POA_BLOCK_TXS_SELECTION_MAX_TIME)); @@ -352,6 +354,7 @@ public void poaBlockTxsSelectionMaxTimeDefaultValue() { public void poaBlockTxsSelectionMaxTimeOption() throws IOException { final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(PositiveNumber.fromInt(80)), @@ -365,6 +368,7 @@ public void poaBlockTxsSelectionMaxTimeOption() throws IOException { public void poaBlockTxsSelectionMaxTimeOptionOver100Percent() throws IOException { final Path genesisFileClique = createFakeGenesisFile(VALID_GENESIS_CLIQUE_POST_LONDON); internalTestSuccess( + this::runtimeConfiguration, miningParams -> { assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(PositiveNumber.fromInt(200)); @@ -412,16 +416,19 @@ protected MiningOptions optionsFromDomainObject(final MiningParameters domainObj @Override protected MiningOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { - final var miningOptions = besuCommand.getMiningOptions(); - miningOptions.setGenesisBlockPeriodSeconds( - besuCommand.getActualGenesisConfigOptions().isPoa() - ? OptionalInt.of(POA_BLOCK_PERIOD_SECONDS) - : OptionalInt.empty()); - return miningOptions; + return besuCommand.getMiningOptions(); } @Override protected String[] getNonOptionFields() { - return new String[] {"maybeGenesisBlockPeriodSeconds", "transactionSelectionService"}; + return new String[] {"transactionSelectionService"}; + } + + private MiningParameters runtimeConfiguration( + final TestBesuCommand besuCommand, final MiningParameters miningParameters) { + if (besuCommand.getActualGenesisConfigOptions().isPoa()) { + miningParameters.setBlockPeriodSeconds(POA_BLOCK_PERIOD_SECONDS); + } + return miningParameters; } } diff --git a/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java new file mode 100644 index 00000000000..bcfe8a2e181 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java @@ -0,0 +1,204 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +import org.hyperledger.besu.config.CheckpointConfigOptions; +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.cryptoservices.NodeKey; +import org.hyperledger.besu.cryptoservices.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.core.Difficulty; +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.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; +import org.hyperledger.besu.ethereum.storage.StorageProvider; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.log.LogsBloomFilter; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.math.BigInteger; +import java.nio.file.Path; +import java.time.Clock; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Range; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public abstract class AbstractBftBesuControllerBuilderTest { + + protected BesuControllerBuilder bftBesuControllerBuilder; + @Mock protected GenesisConfigFile genesisConfigFile; + @Mock protected GenesisConfigOptions genesisConfigOptions; + @Mock private SynchronizerConfiguration synchronizerConfiguration; + @Mock private EthProtocolConfiguration ethProtocolConfiguration; + @Mock CheckpointConfigOptions checkpointConfigOptions; + @Mock private PrivacyParameters privacyParameters; + @Mock private Clock clock; + @Mock private StorageProvider storageProvider; + @Mock private GasLimitCalculator gasLimitCalculator; + @Mock private WorldStatePreimageStorage worldStatePreimageStorage; + private static final BigInteger networkId = BigInteger.ONE; + private static final NodeKey nodeKey = NodeKeyUtils.generate(); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); + protected final ObjectMapper objectMapper = new ObjectMapper(); + private final MiningParameters miningParameters = MiningParameters.newDefault(); + @TempDir Path tempDir; + + @BeforeEach + public void setup() throws JsonProcessingException { + // besu controller setup + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); + lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); + lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); + lenient() + .when(storageProvider.createBlockchainStorage(any(), any())) + .thenReturn( + new KeyValueStoragePrefixedKeyBlockchainStorage( + new InMemoryKeyValueStorage(), + new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), + new MainnetBlockHeaderFunctions())); + lenient() + .when( + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); + lenient() + .when(worldStatePreimageStorage.updater()) + .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); + lenient() + .when(storageProvider.createWorldStatePreimageStorage()) + .thenReturn(worldStatePreimageStorage); + lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); + + lenient() + .when(synchronizerConfiguration.getBlockPropagationRange()) + .thenReturn(Range.closed(1L, 2L)); + + setupBftGenesisConfigOptions(); + + bftBesuControllerBuilder = + createBftControllerBuilder() + .genesisConfigFile(genesisConfigFile) + .synchronizerConfiguration(synchronizerConfiguration) + .ethProtocolConfiguration(ethProtocolConfiguration) + .networkId(networkId) + .miningParameters(miningParameters) + .metricsSystem(observableMetricsSystem) + .privacyParameters(privacyParameters) + .dataDirectory(tempDir) + .clock(clock) + .transactionPoolConfiguration(poolConfiguration) + .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) + .nodeKey(nodeKey) + .storageProvider(storageProvider) + .gasLimitCalculator(gasLimitCalculator) + .evmConfiguration(EvmConfiguration.DEFAULT) + .networkConfiguration(NetworkingConfiguration.create()); + } + + protected abstract void setupBftGenesisConfigOptions() throws JsonProcessingException; + + protected abstract BesuControllerBuilder createBftControllerBuilder(); + + @Test + public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { + final var besuController = bftBesuControllerBuilder.build(); + final var protocolContext = besuController.getProtocolContext(); + + final BlockHeader header1 = + new BlockHeader( + protocolContext.getBlockchain().getChainHeadHash(), + Hash.EMPTY_TRIE_HASH, + Address.ZERO, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + LogsBloomFilter.builder().build(), + Difficulty.ONE, + 1, + 0, + 0, + 0, + protocolContext.getBlockchain().getChainHead().getBlockHeader().getExtraData(), + Wei.ZERO, + Hash.EMPTY, + 0, + null, + null, + null, + null, + null, + getBlockHeaderFunctions()); + final Block block1 = new Block(header1, BlockBody.empty()); + + protocolContext.getBlockchain().appendBlock(block1, List.of()); + + assertThat(miningParameters.getBlockPeriodSeconds()).isNotEmpty().hasValue(2); + assertThat(miningParameters.getBlockTxsSelectionMaxTime()).isEqualTo(2000 * 75 / 100); + } + + protected abstract BlockHeaderFunctions getBlockHeaderFunctions(); +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java new file mode 100644 index 00000000000..b96a052c61a --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java @@ -0,0 +1,231 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.CheckpointConfigOptions; +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.config.ImmutableCliqueConfigOptions; +import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.clique.CliqueBlockHeaderFunctions; +import org.hyperledger.besu.cryptoservices.NodeKey; +import org.hyperledger.besu.cryptoservices.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; +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.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; +import org.hyperledger.besu.ethereum.storage.StorageProvider; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.log.LogsBloomFilter; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.math.BigInteger; +import java.nio.file.Path; +import java.time.Clock; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Range; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class CliqueBesuControllerBuilderTest { + + private BesuControllerBuilder cliqueBesuControllerBuilder; + + @Mock private GenesisConfigFile genesisConfigFile; + @Mock private GenesisConfigOptions genesisConfigOptions; + @Mock private SynchronizerConfiguration synchronizerConfiguration; + @Mock private EthProtocolConfiguration ethProtocolConfiguration; + @Mock private CheckpointConfigOptions checkpointConfigOptions; + @Mock private PrivacyParameters privacyParameters; + @Mock private Clock clock; + @Mock private StorageProvider storageProvider; + @Mock private GasLimitCalculator gasLimitCalculator; + @Mock private WorldStatePreimageStorage worldStatePreimageStorage; + private static final BigInteger networkId = BigInteger.ONE; + private static final NodeKey nodeKey = NodeKeyUtils.generate(); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); + private final ObjectMapper objectMapper = new ObjectMapper(); + private final MiningParameters miningParameters = MiningParameters.newDefault(); + + @TempDir Path tempDir; + + @BeforeEach + public void setup() throws JsonProcessingException { + // Clique Besu controller setup + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); + when(genesisConfigFile.getExtraData()) + .thenReturn( + "0x0000000000000000000000000000000000000000000000000000000000000000b9b81ee349c3807e46bc71aa2632203c5b4620340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); + lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); + lenient() + .when(storageProvider.createBlockchainStorage(any(), any())) + .thenReturn( + new KeyValueStoragePrefixedKeyBlockchainStorage( + new InMemoryKeyValueStorage(), + new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), + new MainnetBlockHeaderFunctions())); + lenient() + .when( + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); + lenient() + .when(worldStatePreimageStorage.updater()) + .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); + lenient() + .when(storageProvider.createWorldStatePreimageStorage()) + .thenReturn(worldStatePreimageStorage); + lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); + + lenient() + .when(synchronizerConfiguration.getBlockPropagationRange()) + .thenReturn(Range.closed(1L, 2L)); + + // clique prepForBuild setup + lenient() + .when(genesisConfigOptions.getCliqueConfigOptions()) + .thenReturn( + ImmutableCliqueConfigOptions.builder() + .epochLength(30) + .createEmptyBlocks(true) + .blockPeriodSeconds(1) + .build()); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"clique": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + + lenient() + .when(genesisConfigOptions.getTransitions()) + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + + cliqueBesuControllerBuilder = + new CliqueBesuControllerBuilder() + .genesisConfigFile(genesisConfigFile) + .synchronizerConfiguration(synchronizerConfiguration) + .ethProtocolConfiguration(ethProtocolConfiguration) + .networkId(networkId) + .miningParameters(miningParameters) + .metricsSystem(observableMetricsSystem) + .privacyParameters(privacyParameters) + .dataDirectory(tempDir) + .clock(clock) + .transactionPoolConfiguration(poolConfiguration) + .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) + .nodeKey(nodeKey) + .storageProvider(storageProvider) + .gasLimitCalculator(gasLimitCalculator) + .evmConfiguration(EvmConfiguration.DEFAULT) + .networkConfiguration(NetworkingConfiguration.create()); + } + + @Test + public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { + final var besuController = cliqueBesuControllerBuilder.build(); + final var protocolContext = besuController.getProtocolContext(); + + final BlockHeader header1 = + new BlockHeader( + protocolContext.getBlockchain().getChainHeadHash(), + Hash.EMPTY_TRIE_HASH, + Address.ZERO, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + LogsBloomFilter.builder().build(), + Difficulty.ONE, + 1, + 0, + 0, + 0, + Bytes.EMPTY, + Wei.ZERO, + Hash.EMPTY, + 0, + null, + null, + null, + null, + null, + new CliqueBlockHeaderFunctions()); + final Block block1 = new Block(header1, BlockBody.empty()); + + protocolContext.getBlockchain().appendBlock(block1, List.of()); + + assertThat(miningParameters.getBlockPeriodSeconds()).isNotEmpty().hasValue(2); + assertThat(miningParameters.getBlockTxsSelectionMaxTime()).isEqualTo(2000 * 75 / 100); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java new file mode 100644 index 00000000000..a819a140311 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java @@ -0,0 +1,73 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.JsonBftConfigOptions; +import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions; +import org.hyperledger.besu.consensus.common.bft.MutableBftConfigOptions; +import org.hyperledger.besu.consensus.ibft.IbftExtraDataCodec; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class IbftBesuControllerBuilderTest extends AbstractBftBesuControllerBuilderTest { + + @Override + public void setupBftGenesisConfigOptions() throws JsonProcessingException { + + // Ibft prepForBuild setup + lenient() + .when(genesisConfigOptions.getBftConfigOptions()) + .thenReturn(new MutableBftConfigOptions(JsonBftConfigOptions.DEFAULT)); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"ibft2": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + + lenient() + .when(genesisConfigOptions.getTransitions()) + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + + when(genesisConfigFile.getExtraData()) + .thenReturn( + "0xf83ea00000000000000000000000000000000000000000000000000000000000000000d594c2ab482b506de561668e07f04547232a72897daf808400000000c0"); + } + + @Override + protected BesuControllerBuilder createBftControllerBuilder() { + return new IbftBesuControllerBuilder(); + } + + @Override + protected BlockHeaderFunctions getBlockHeaderFunctions() { + return BftBlockHeaderFunctions.forOnchainBlock(new IbftExtraDataCodec()); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java index e768c49e567..e3e99285b66 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java @@ -16,167 +16,77 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.config.CheckpointConfigOptions; -import org.hyperledger.besu.config.GenesisConfigFile; -import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.JsonQbftConfigOptions; import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions; import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.MutableQbftConfigOptions; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider; -import org.hyperledger.besu.cryptoservices.NodeKey; -import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -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.sync.SynchronizerConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; -import org.hyperledger.besu.ethereum.storage.StorageProvider; -import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; -import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; -import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; -import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; - -import java.math.BigInteger; -import java.nio.file.Path; -import java.time.Clock; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; + import java.util.List; -import com.google.common.collect.Range; -import org.apache.tuweni.bytes.Bytes; -import org.junit.jupiter.api.BeforeEach; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class QbftBesuControllerBuilderTest { - - private BesuControllerBuilder qbftBesuControllerBuilder; - - @Mock private GenesisConfigFile genesisConfigFile; - @Mock private GenesisConfigOptions genesisConfigOptions; - @Mock private SynchronizerConfiguration synchronizerConfiguration; - @Mock private EthProtocolConfiguration ethProtocolConfiguration; - @Mock CheckpointConfigOptions checkpointConfigOptions; - @Mock private MiningParameters miningParameters; - @Mock private PrivacyParameters privacyParameters; - @Mock private Clock clock; - @Mock private StorageProvider storageProvider; - @Mock private GasLimitCalculator gasLimitCalculator; - @Mock private WorldStatePreimageStorage worldStatePreimageStorage; - private static final BigInteger networkId = BigInteger.ONE; - private static final NodeKey nodeKey = NodeKeyUtils.generate(); - private final TransactionPoolConfiguration poolConfiguration = - TransactionPoolConfiguration.DEFAULT; - private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); - - @TempDir Path tempDir; - - @BeforeEach - public void setup() { - // besu controller setup - final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = - mock(ForestWorldStateKeyValueStorage.class); - final WorldStateStorageCoordinator worldStateStorageCoordinator = - new WorldStateStorageCoordinator(worldStateKeyValueStorage); - - lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); - lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); - when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString()); - lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); - lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); - lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); - lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); - lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); - lenient() - .when(storageProvider.createBlockchainStorage(any(), any())) - .thenReturn( - new KeyValueStoragePrefixedKeyBlockchainStorage( - new InMemoryKeyValueStorage(), - new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), - new MainnetBlockHeaderFunctions())); +public class QbftBesuControllerBuilderTest extends AbstractBftBesuControllerBuilderTest { - lenient() - .when( - storageProvider.createWorldStateStorageCoordinator( - DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) - .thenReturn(worldStateStorageCoordinator); - lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); - lenient() - .when(worldStateKeyValueStorage.updater()) - .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); - lenient() - .when(worldStatePreimageStorage.updater()) - .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); - lenient() - .when(storageProvider.createWorldStatePreimageStorage()) - .thenReturn(worldStatePreimageStorage); - lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); - lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); - lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); - - lenient() - .when(synchronizerConfiguration.getBlockPropagationRange()) - .thenReturn(Range.closed(1L, 2L)); + @Override + public void setupBftGenesisConfigOptions() throws JsonProcessingException { // qbft prepForBuild setup lenient() .when(genesisConfigOptions.getQbftConfigOptions()) .thenReturn(new MutableQbftConfigOptions(JsonQbftConfigOptions.DEFAULT)); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"qbft": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + lenient() .when(genesisConfigOptions.getTransitions()) - .thenReturn(mock(TransitionsConfigOptions.class)); + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + lenient() .when(genesisConfigFile.getExtraData()) .thenReturn( QbftExtraDataCodec.createGenesisExtraDataString(List.of(Address.fromHexString("1")))); + } + + @Override + protected BesuControllerBuilder createBftControllerBuilder() { + return new QbftBesuControllerBuilder(); + } - qbftBesuControllerBuilder = - new QbftBesuControllerBuilder() - .genesisConfigFile(genesisConfigFile) - .synchronizerConfiguration(synchronizerConfiguration) - .ethProtocolConfiguration(ethProtocolConfiguration) - .networkId(networkId) - .miningParameters(miningParameters) - .metricsSystem(observableMetricsSystem) - .privacyParameters(privacyParameters) - .dataDirectory(tempDir) - .clock(clock) - .transactionPoolConfiguration(poolConfiguration) - .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) - .nodeKey(nodeKey) - .storageProvider(storageProvider) - .gasLimitCalculator(gasLimitCalculator) - .evmConfiguration(EvmConfiguration.DEFAULT) - .networkConfiguration(NetworkingConfiguration.create()); + @Override + protected BlockHeaderFunctions getBlockHeaderFunctions() { + return BftBlockHeaderFunctions.forOnchainBlock(new QbftExtraDataCodec()); } @Test public void forkingValidatorProviderIsAvailableOnBftContext() { - final BesuController besuController = qbftBesuControllerBuilder.build(); + final BesuController besuController = bftBesuControllerBuilder.build(); final ValidatorProvider validatorProvider = besuController @@ -192,7 +102,7 @@ public void missingTransactionValidatorProviderThrowsError() { when(protocolContext.getBlockchain()).thenReturn(mock(MutableBlockchain.class)); assertThatThrownBy( - () -> qbftBesuControllerBuilder.createAdditionalJsonRpcMethodFactory(protocolContext)) + () -> bftBesuControllerBuilder.createAdditionalJsonRpcMethodFactory(protocolContext)) .isInstanceOf(NullPointerException.class) .hasMessage("transactionValidatorProvider should have been initialised"); } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java index 8421ac3f195..fddcce39091 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java @@ -42,7 +42,6 @@ import org.junit.jupiter.api.Test; public class CliqueBlockSchedulerTest { - private final KeyPair proposerKeyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair(); private Address localAddr; diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index ebca2bb17aa..4c843b2eaea 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -1405,9 +1405,9 @@ protected MiningParameters createMiningParameters( MutableInitValues.builder() .minTransactionGasPrice(minGasPrice) .minBlockOccupancyRatio(minBlockOccupancyRatio) + .blockPeriodSeconds(genesisBlockPeriodSeconds) .build()) .transactionSelectionService(transactionSelectionService) - .genesisBlockPeriodSeconds(genesisBlockPeriodSeconds) .poaBlockTxsSelectionMaxTime(minBlockTimePercentage) .build(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java index 0a7144d30d9..febce15fe13 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java @@ -122,6 +122,15 @@ public MiningParameters setNonceGenerator(final Iterable nonceGenerator) { return this; } + public OptionalInt getBlockPeriodSeconds() { + return getMutableRuntimeValues().blockPeriodSeconds; + } + + public MiningParameters setBlockPeriodSeconds(final int blockPeriodSeconds) { + getMutableRuntimeValues().blockPeriodSeconds = OptionalInt.of(blockPeriodSeconds); + return this; + } + @Value.Default public boolean isStratumMiningEnabled() { return false; @@ -161,12 +170,10 @@ public void registerPluginTransactionSelectorFactory( }; } - public abstract OptionalInt getGenesisBlockPeriodSeconds(); - - @Value.Derived public long getBlockTxsSelectionMaxTime() { - if (getGenesisBlockPeriodSeconds().isPresent()) { - return (TimeUnit.SECONDS.toMillis(getGenesisBlockPeriodSeconds().getAsInt()) + final var maybeBlockPeriodSeconds = getMutableRuntimeValues().blockPeriodSeconds; + if (maybeBlockPeriodSeconds.isPresent()) { + return (TimeUnit.SECONDS.toMillis(maybeBlockPeriodSeconds.getAsInt()) * getPoaBlockTxsSelectionMaxTime().getValue()) / 100; } @@ -222,6 +229,8 @@ default double getMinBlockOccupancyRatio() { return DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; } + OptionalInt getBlockPeriodSeconds(); + Optional
getCoinbase(); OptionalLong getTargetGasLimit(); @@ -238,6 +247,7 @@ static class MutableRuntimeValues { private volatile Optional
coinbase; private volatile OptionalLong targetGasLimit; private volatile Optional> nonceGenerator; + private volatile OptionalInt blockPeriodSeconds; private MutableRuntimeValues(final MutableInitValues initValues) { miningEnabled = initValues.isMiningEnabled(); @@ -248,6 +258,7 @@ private MutableRuntimeValues(final MutableInitValues initValues) { coinbase = initValues.getCoinbase(); targetGasLimit = initValues.getTargetGasLimit(); nonceGenerator = initValues.nonceGenerator(); + blockPeriodSeconds = initValues.getBlockPeriodSeconds(); } @Override @@ -262,7 +273,8 @@ public boolean equals(final Object o) { && Objects.equals(coinbase, that.coinbase) && Objects.equals(minPriorityFeePerGas, that.minPriorityFeePerGas) && Objects.equals(targetGasLimit, that.targetGasLimit) - && Objects.equals(nonceGenerator, that.nonceGenerator); + && Objects.equals(nonceGenerator, that.nonceGenerator) + && Objects.equals(blockPeriodSeconds, that.blockPeriodSeconds); } @Override @@ -275,7 +287,8 @@ public int hashCode() { minBlockOccupancyRatio, coinbase, targetGasLimit, - nonceGenerator); + nonceGenerator, + blockPeriodSeconds); } @Override @@ -297,6 +310,8 @@ public String toString() { + targetGasLimit + ", nonceGenerator=" + nonceGenerator + + ", blockPeriodSeconds=" + + blockPeriodSeconds + '}'; } }