Skip to content
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

Improve genesis state performance at startup #6977

Merged
merged 27 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
aca87fa
Refactor genesis options file management
fab-10 Apr 17, 2024
158bb6b
Make loading allocation from genesis lazy
fab-10 Apr 19, 2024
2e34b86
Update tests
fab-10 Apr 19, 2024
1bc5402
Memory optimization with streaming
fab-10 Apr 22, 2024
252c2fc
Improve loading and storgin genesis state at startup
fab-10 Apr 22, 2024
1f8f856
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 22, 2024
5bee14b
Remove comments
fab-10 Apr 23, 2024
fa222f0
Avoid parsing genesis file allocations twice
fab-10 Apr 23, 2024
aee4a37
Update javadoc
fab-10 Apr 23, 2024
51aceae
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 23, 2024
d8ed865
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 23, 2024
5548219
Fix
fab-10 Apr 23, 2024
e9dc288
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 24, 2024
843c95d
Merge branch 'refactor-genesis-file-options' of github.com:fab-10/bes…
fab-10 Apr 24, 2024
42be9c5
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 24, 2024
fb1f568
Fix
fab-10 Apr 24, 2024
0889ee4
Ignore unknown objects in allocations
fab-10 Apr 24, 2024
a79c0f5
Merge branch 'main' into refactor-genesis-file-options
fab-10 Apr 29, 2024
b3a8978
Merge branch 'main' into refactor-genesis-file-options
fab-10 May 2, 2024
2834719
Merge branch 'main' into refactor-genesis-file-options
fab-10 May 3, 2024
910c07b
Merge branch 'main' into refactor-genesis-file-options
fab-10 May 31, 2024
a662895
avoid keeping genesis allocation data in memory
fab-10 May 31, 2024
e8ff18a
Update CHANGELOG
fab-10 Jun 3, 2024
ec49c69
Merge branch 'main' into refactor-genesis-file-options
fab-10 Jun 3, 2024
3986788
Merge branch 'main' into refactor-genesis-file-options
ahamlat Jun 10, 2024
b6b5a85
Merge branch 'main' into refactor-genesis-file-options
fab-10 Jun 11, 2024
0dea5c8
Merge branch 'main' into refactor-genesis-file-options
fab-10 Jun 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

### Additions and Improvements
- Add two counters to DefaultBlockchain in order to be able to calculate TPS and Mgas/s [#7105](https://github.com/hyperledger/besu/pull/7105)
- Improve genesis state performance at startup [#6977](https://github.com/hyperledger/besu/pull/6977)
- Enable --Xbonsai-limit-trie-logs-enabled by default, unless sync-mode=FULL [#7181](https://github.com/hyperledger/besu/pull/7181)
- Promote experimental --Xbonsai-limit-trie-logs-enabled to production-ready, --bonsai-limit-trie-logs-enabled [#7192](https://github.com/hyperledger/besu/pull/7192)
- Promote experimental --Xbonsai-trie-logs-pruning-window-size to production-ready, --bonsai-trie-logs-pruning-window-size [#7192](https://github.com/hyperledger/besu/pull/7192)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.chain.VariablesStorage;
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;
Expand Down Expand Up @@ -552,37 +553,23 @@ public BesuController build() {
prepForBuild();

final ProtocolSchedule protocolSchedule = createProtocolSchedule();
final GenesisState genesisState;

final VariablesStorage variablesStorage = storageProvider.createVariablesStorage();

Optional<Hash> genesisStateHash = Optional.empty();
if (variablesStorage != null && this.genesisStateHashCacheEnabled) {
genesisStateHash = variablesStorage.getGenesisStateHash();
}

if (genesisStateHash.isPresent()) {
genesisState =
GenesisState.fromConfig(genesisStateHash.get(), genesisConfigFile, protocolSchedule);
} else {
genesisState =
GenesisState.fromConfig(dataStorageConfiguration, genesisConfigFile, protocolSchedule);
if (variablesStorage != null) {
VariablesStorage.Updater updater = variablesStorage.updater();
if (updater != null) {
updater.setGenesisStateHash(genesisState.getBlock().getHeader().getStateRoot());
updater.commit();
}
}
}

final WorldStateStorageCoordinator worldStateStorageCoordinator =
storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration);

final BlockchainStorage blockchainStorage =
storageProvider.createBlockchainStorage(
protocolSchedule, variablesStorage, dataStorageConfiguration);

final var maybeStoredGenesisBlockHash = blockchainStorage.getBlockHash(0L);

final var genesisState =
getGenesisState(
maybeStoredGenesisBlockHash.flatMap(blockchainStorage::getBlockHeader),
protocolSchedule);

final MutableBlockchain blockchain =
DefaultBlockchain.createMutable(
genesisState.getBlock(),
Expand All @@ -591,7 +578,6 @@ public BesuController build() {
reorgLoggingThreshold,
dataDirectory.toString(),
numberOfBlocksToCache);

final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader =
besuComponent
.map(BesuComponent::getCachedMerkleTrieLoader)
Expand All @@ -601,7 +587,7 @@ public BesuController build() {
createWorldStateArchive(
worldStateStorageCoordinator, blockchain, bonsaiCachedMerkleTrieLoader);

if (blockchain.getChainHeadBlockNumber() < 1) {
if (maybeStoredGenesisBlockHash.isEmpty()) {
genesisState.writeStateTo(worldStateArchive.getMutable());
}

Expand Down Expand Up @@ -772,6 +758,24 @@ public BesuController build() {
dataStorageConfiguration);
}

private GenesisState getGenesisState(
final Optional<BlockHeader> maybeGenesisBlockHeader,
final ProtocolSchedule protocolSchedule) {
final Optional<Hash> maybeGenesisStateRoot =
genesisStateHashCacheEnabled
? maybeGenesisBlockHeader.map(BlockHeader::getStateRoot)
: Optional.empty();

return maybeGenesisStateRoot
.map(
genesisStateRoot ->
GenesisState.fromStorage(genesisStateRoot, genesisConfigFile, protocolSchedule))
.orElseGet(
() ->
GenesisState.fromConfig(
dataStorageConfiguration, genesisConfigFile, protocolSchedule));
}

private TrieLogPruner createTrieLogPruner(
final WorldStateKeyValueStorage worldStateStorage,
final Blockchain blockchain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
Expand Down Expand Up @@ -138,7 +137,7 @@ public static Collection<Object[]> parameters() {
@MethodSource("parameters")
public void testForkId(final NetworkName chainName, final List<ForkId> expectedForkIds) {
final GenesisConfigFile genesisConfigFile =
GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName));
GenesisConfigFile.fromResource(chainName.getGenesisFile());
final MilestoneStreamingTransitionProtocolSchedule schedule = createSchedule(genesisConfigFile);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule);
final Blockchain mockBlockchain = mock(Blockchain.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.config;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;

import java.util.Map;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;

/**
* Genesis account
*
* @param address of the account
* @param nonce nonce of the account at genesis
* @param balance balance of the account at genesis
* @param code code of the account at genesis, can be null
* @param storage storage of the account at genesis
* @param privateKey of the account, only use for testing
*/
public record GenesisAccount(
Address address,
long nonce,
Wei balance,
Bytes code,
Map<UInt256, UInt256> storage,
Bytes32 privateKey) {}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.config;

import static org.hyperledger.besu.config.JsonUtil.normalizeKeys;

import org.hyperledger.besu.datatypes.Wei;

import java.net.URL;
Expand All @@ -30,22 +28,23 @@
import java.util.stream.Stream;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Streams;

/** The Genesis config file. */
public class GenesisConfigFile {

/** The constant DEFAULT. */
public static final GenesisConfigFile DEFAULT =
new GenesisConfigFile(JsonUtil.createEmptyObjectNode());
new GenesisConfigFile(new GenesisReader.FromObjectNode(JsonUtil.createEmptyObjectNode()));

/** The constant BASEFEE_AT_GENESIS_DEFAULT_VALUE. */
public static final Wei BASEFEE_AT_GENESIS_DEFAULT_VALUE = Wei.of(1_000_000_000L);

private final GenesisReader loader;
private final ObjectNode genesisRoot;

private GenesisConfigFile(final ObjectNode config) {
this.genesisRoot = config;
private GenesisConfigFile(final GenesisReader loader) {
this.loader = loader;
this.genesisRoot = loader.getRoot();
}

/**
Expand All @@ -70,21 +69,31 @@ public static GenesisConfigFile fromSource(final URL jsonSource) {
/**
* Genesis file from resource.
*
* @param jsonResource the resource name
* @param resourceName the resource name
* @return the genesis config file
*/
public static GenesisConfigFile fromResource(final String resourceName) {
return fromConfig(GenesisConfigFile.class.getResource(resourceName));
}

/**
* From config genesis config file.
*
* @param jsonSource the json string
* @return the genesis config file
*/
public static GenesisConfigFile fromResource(final String jsonResource) {
return fromSource(GenesisConfigFile.class.getResource(jsonResource));
public static GenesisConfigFile fromConfig(final URL jsonSource) {
return new GenesisConfigFile(new GenesisReader.FromURL(jsonSource));
}

/**
* From config genesis config file.
*
* @param jsonString the json string
* @param json the json string
* @return the genesis config file
*/
public static GenesisConfigFile fromConfig(final String jsonString) {
return fromConfig(JsonUtil.objectNodeFromString(jsonString, false));
public static GenesisConfigFile fromConfig(final String json) {
return fromConfig(JsonUtil.objectNodeFromString(json, false));
}

/**
Expand All @@ -94,7 +103,7 @@ public static GenesisConfigFile fromConfig(final String jsonString) {
* @return the genesis config file
*/
public static GenesisConfigFile fromConfig(final ObjectNode config) {
return new GenesisConfigFile(normalizeKeys(config));
return new GenesisConfigFile(new GenesisReader.FromObjectNode(config));
}

/**
Expand All @@ -113,8 +122,7 @@ public GenesisConfigOptions getConfigOptions() {
* @return the config options
*/
public GenesisConfigOptions getConfigOptions(final Map<String, String> overrides) {
final ObjectNode config =
JsonUtil.getObjectNode(genesisRoot, "config").orElse(JsonUtil.createEmptyObjectNode());
final ObjectNode config = loader.getConfig();

Map<String, String> overridesRef = overrides;

Expand All @@ -134,15 +142,8 @@ public GenesisConfigOptions getConfigOptions(final Map<String, String> overrides
*
* @return the stream
*/
public Stream<GenesisAllocation> streamAllocations() {
return JsonUtil.getObjectNode(genesisRoot, "alloc").stream()
.flatMap(
allocations ->
Streams.stream(allocations.fieldNames())
.map(
key ->
new GenesisAllocation(
key, JsonUtil.getObjectNode(allocations, key).get())));
public Stream<GenesisAccount> streamAllocations() {
return loader.streamAllocations();
}

/**
Expand Down Expand Up @@ -344,7 +345,7 @@ public String toString() {
+ "genesisRoot="
+ genesisRoot
+ ", allocations="
+ streamAllocations().map(GenesisAllocation::toString).collect(Collectors.joining(","))
+ loader.streamAllocations().map(GenesisAccount::toString).collect(Collectors.joining(","))
+ '}';
}
}
Loading
Loading