-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add chain data pruning experimental feature #4686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
fce33c1
be8f081
af59579
16de0e9
3e67042
0d433a3
0e545c5
4e0e627
9313b02
3e3596b
d0807ff
4c1d792
95e86a5
a63542a
580942a
328005b
c34154f
64ba456
a42a933
322b327
cd37f0f
ac79611
51c6c6d
96c2934
cbc460b
99b273f
cc4648e
8315393
5992b66
5d4da4e
118178e
91102a7
962adb6
1368c55
d41661b
2a439f1
d29a286
e2c088c
25d514d
571a022
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,6 +56,7 @@ | |
| import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; | ||
| import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption; | ||
| import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions; | ||
| import org.hyperledger.besu.cli.options.unstable.ChainDataPruningOptions; | ||
| import org.hyperledger.besu.cli.options.unstable.DnsOptions; | ||
| import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; | ||
| import org.hyperledger.besu.cli.options.unstable.EvmOptions; | ||
|
|
@@ -288,6 +289,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable { | |
| private final PrivacyPluginOptions unstablePrivacyPluginOptions = PrivacyPluginOptions.create(); | ||
| private final EvmOptions unstableEvmOptions = EvmOptions.create(); | ||
| private final IpcOptions unstableIpcOptions = IpcOptions.create(); | ||
| private final ChainDataPruningOptions unstableChainDataPruningOptions = | ||
| ChainDataPruningOptions.create(); | ||
|
|
||
| // stable CLI options | ||
| private final DataStorageOptions dataStorageOptions = DataStorageOptions.create(); | ||
|
|
@@ -1529,6 +1532,7 @@ private void handleUnstableOptions() { | |
| .put("Launcher", unstableLauncherOptions) | ||
| .put("EVM Options", unstableEvmOptions) | ||
| .put("IPC Options", unstableIpcOptions) | ||
| .put("Chain Data Pruning Options", unstableChainDataPruningOptions) | ||
| .build(); | ||
|
|
||
| UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions); | ||
|
|
@@ -1756,6 +1760,7 @@ private void validateOptions() { | |
| validateDnsOptionsParams(); | ||
| ensureValidPeerBoundParams(); | ||
| validateRpcOptionsParams(); | ||
| validateChainDataPruningParams(); | ||
| p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); | ||
| pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); | ||
| } | ||
|
|
@@ -1894,6 +1899,20 @@ public void validateRpcOptionsParams() { | |
| } | ||
| } | ||
|
|
||
| public void validateChainDataPruningParams() { | ||
|
siladu marked this conversation as resolved.
|
||
| if (Boolean.TRUE.equals(unstableChainDataPruningOptions.getChainDataPruningEnabled())) { | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| if (unstableChainDataPruningOptions.getChainDataPruningBlocksRetained() | ||
| < ChainDataPruningOptions.DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED) { | ||
| throw new ParameterException( | ||
| this.commandLine, "--Xchain-data-pruning-blocks-retained must be >= 50400"); | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| } | ||
| if (unstableChainDataPruningOptions.getChainDataPruningBlocksFrequency() < 0) { | ||
| throw new ParameterException( | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| this.commandLine, "--Xchain-data-pruning-frequency must be non-negative"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private GenesisConfigOptions readGenesisConfigOptions() { | ||
|
|
||
| try { | ||
|
|
@@ -2149,7 +2168,12 @@ public BesuControllerBuilder getControllerBuilder() { | |
| .reorgLoggingThreshold(reorgLoggingThreshold) | ||
| .evmConfiguration(unstableEvmOptions.toDomainObject()) | ||
| .dataStorageConfiguration(dataStorageOptions.toDomainObject()) | ||
| .maxPeers(p2PDiscoveryOptionGroup.maxPeers); | ||
| .maxPeers(p2PDiscoveryOptionGroup.maxPeers) | ||
| .isChainDataPruningEnabled(unstableChainDataPruningOptions.getChainDataPruningEnabled()) | ||
| .chainDataPruningBlocksRetained( | ||
| unstableChainDataPruningOptions.getChainDataPruningBlocksRetained()) | ||
| .chainDataPruningFrequency( | ||
| unstableChainDataPruningOptions.getChainDataPruningBlocksFrequency()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can domain object be created instead so that 3 values don't need to passed through
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
| } | ||
|
|
||
| private GraphQLConfiguration graphQLConfiguration() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| /* | ||
| * 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.cli.options.unstable; | ||
|
|
||
| import picocli.CommandLine; | ||
|
|
||
| public class ChainDataPruningOptions { | ||
|
|
||
| public static final long DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED = 50400; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to avoid this magic value? If syncing takes longer than a week then this will fail?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, ideally if the pruner has the syncing context to know the current pivot block and if the syncing has finished, then it can avoid pruning beyond the pivot block before syncing is completed. Do you think we should do it in a separate ticket?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should do this in another ticket.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename to MAX_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED? This not just the default but also the maximum number of blocks that will be pruned.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually the minimum value for the blocks to retain. I've also changed it to be much smaller. |
||
| public static final long DEFAULT_CHAIN_DATA_PRUNING_FREQUENCY = 256; | ||
|
|
||
| @CommandLine.Option( | ||
| hidden = true, | ||
| names = {"--Xchain-data-pruning-enabled"}, | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| description = | ||
| "Enable the chain pruner to actively prune old chain data (default: ${DEFAULT-VALUE})") | ||
| private final Boolean chainDataPruningEnabled = Boolean.FALSE; | ||
|
|
||
| @CommandLine.Option( | ||
| hidden = true, | ||
| names = {"--Xchain-data-pruning-blocks-retained"}, | ||
| description = | ||
| "The number of recent blocks for which to keep the chain data. Must be >= 50400 (default: ${DEFAULT-VALUE})") | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| private final Long chainDataPruningBlocksRetained = | ||
| DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED; | ||
|
|
||
| @CommandLine.Option( | ||
| hidden = true, | ||
| names = {"--Xchain-data-pruning-frequency"}, | ||
| description = | ||
| "The number of blocks added to the chain between two pruning operations. Must be non-negative (default: ${DEFAULT-VALUE})") | ||
| private final Long chainDataPruningBlocksFrequency = DEFAULT_CHAIN_DATA_PRUNING_FREQUENCY; | ||
|
|
||
| public static ChainDataPruningOptions create() { | ||
| return new ChainDataPruningOptions(); | ||
| } | ||
|
|
||
| public Boolean getChainDataPruningEnabled() { | ||
| return chainDataPruningEnabled; | ||
| } | ||
|
|
||
| public Long getChainDataPruningBlocksRetained() { | ||
| return chainDataPruningBlocksRetained; | ||
| } | ||
|
|
||
| public Long getChainDataPruningBlocksFrequency() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason this type doesn't match the PositiveNumber type above?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converting and returning long makes it easy to compare with block number (also in long) in use of outside. Using Positive number is to ensure user can only supply positive frequency. |
||
| return chainDataPruningBlocksFrequency; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ | |
| import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage; | ||
| import org.hyperledger.besu.ethereum.chain.Blockchain; | ||
| import org.hyperledger.besu.ethereum.chain.BlockchainStorage; | ||
| import org.hyperledger.besu.ethereum.chain.ChainDataPruner; | ||
| import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; | ||
| import org.hyperledger.besu.ethereum.chain.GenesisState; | ||
| import org.hyperledger.besu.ethereum.chain.MutableBlockchain; | ||
|
|
@@ -139,6 +140,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides | |
| Collections.emptyList(); | ||
| protected EvmConfiguration evmConfiguration; | ||
| protected int maxPeers; | ||
| protected boolean isChainDataPruningEnabled; | ||
| protected long chainDataPruningBlocksRetained; | ||
| protected long chainDataPruningFrequency; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could maybe wrap in a ChainDataPruningConfiguration object?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
|
||
| public BesuControllerBuilder storageProvider(final StorageProvider storageProvider) { | ||
| this.storageProvider = storageProvider; | ||
|
|
@@ -267,6 +271,22 @@ public BesuControllerBuilder maxPeers(final int maxPeers) { | |
| return this; | ||
| } | ||
|
|
||
| public BesuControllerBuilder isChainDataPruningEnabled(final boolean isChainDataPruningEnabled) { | ||
| this.isChainDataPruningEnabled = isChainDataPruningEnabled; | ||
| return this; | ||
| } | ||
|
|
||
| public BesuControllerBuilder chainDataPruningBlocksRetained( | ||
| final long chainDataPruningBlocksRetained) { | ||
| this.chainDataPruningBlocksRetained = chainDataPruningBlocksRetained; | ||
| return this; | ||
| } | ||
|
|
||
| public BesuControllerBuilder chainDataPruningFrequency(final long chainDataPruningFrequency) { | ||
| this.chainDataPruningFrequency = chainDataPruningFrequency; | ||
| return this; | ||
| } | ||
|
|
||
| public BesuController build() { | ||
| checkNotNull(genesisConfig, "Missing genesis config"); | ||
| checkNotNull(syncConfig, "Missing sync config"); | ||
|
|
@@ -300,6 +320,23 @@ public BesuController build() { | |
| reorgLoggingThreshold, | ||
| dataDirectory.toString()); | ||
|
|
||
| if (isChainDataPruningEnabled) { | ||
| ChainDataPruner.enablePruning(); | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| ChainDataPruner chainDataPruner = | ||
|
wcgcyx marked this conversation as resolved.
Outdated
|
||
| new ChainDataPruner( | ||
| blockchainStorage, | ||
| storageProvider.getStorageBySegmentIdentifier( | ||
| KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE), | ||
| chainDataPruningBlocksRetained, | ||
| chainDataPruningFrequency); | ||
| blockchain.observeBlockAdded(chainDataPruner); | ||
| LOG.info( | ||
| "Chain data pruning enabled with recent blocks retained to be: " | ||
| + chainDataPruningBlocksRetained | ||
| + " and frequency to be: " | ||
| + chainDataPruningFrequency); | ||
| } | ||
|
|
||
| final WorldStateArchive worldStateArchive = | ||
| createWorldStateArchive(worldStateStorage, blockchain); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ | |
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineUpdateForkchoiceResult; | ||
| import org.hyperledger.besu.ethereum.chain.ChainDataPruner; | ||
| import org.hyperledger.besu.ethereum.core.BlockHeader; | ||
|
|
||
| import java.util.Optional; | ||
|
|
@@ -116,7 +117,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) | |
| } | ||
|
|
||
| // TODO: post-merge cleanup, this should be unnecessary after merge | ||
| if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead.get())) { | ||
| if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead.get()) | ||
| && !ChainDataPruner.isPruningEnabled()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nicer to drive this based on the chain data pruning enabled flag rather than setting and using a static global field
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, I tried that a bit but it seems like that would involve bringing besu command into the protocol context. I consider it to be a temporary solution until #4703 is merged. Then, we could just do a cleanup to get rid of this global field completely.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't need to bring the entire Besu command into the protocol context. At most, the chain pruning config values would need to be passed through. A compromise could be to make the ChainPruner a singleton instead.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, It seems cleaner to add a flag in merge context instead, following what @gfukushima did in #4735
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated to have a temporary flag in protocol context instead. Global variable gets removed. |
||
| logForkchoiceUpdatedCall(INVALID, forkChoice); | ||
| return new JsonRpcSuccessResponse( | ||
| requestId, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.