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

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -549,37 +550,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 @@ -588,7 +575,6 @@ public BesuController build() {
reorgLoggingThreshold,
dataDirectory.toString(),
numberOfBlocksToCache);

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

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

Expand Down Expand Up @@ -769,6 +755,20 @@ public BesuController build() {
dataStorageConfiguration);
}

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

if (genesisStateHash.isPresent()) {
return GenesisState.fromStorage(genesisStateHash.get(), genesisConfigFile, protocolSchedule);
}
return GenesisState.fromConfig(dataStorageConfiguration, genesisConfigFile, protocolSchedule);
}

private TrieLogPruner createTrieLogPruner(
final WorldStateKeyValueStorage worldStateStorage,
final Blockchain blockchain,
Expand Down
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 @@ -149,7 +148,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
Expand Up @@ -107,19 +107,21 @@ public void setup() throws JsonProcessingException {
lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions);
lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions);
lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions);
final var variableStorage = new VariablesKeyValueStorage(new InMemoryKeyValueStorage());
lenient()
.when(storageProvider.createBlockchainStorage(any(), any(), any()))
.thenReturn(
new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(),
new VariablesKeyValueStorage(new InMemoryKeyValueStorage()),
variableStorage,
new MainnetBlockHeaderFunctions(),
false));
lenient()
.when(
storageProvider.createWorldStateStorageCoordinator(
DataStorageConfiguration.DEFAULT_FOREST_CONFIG))
.thenReturn(worldStateStorageCoordinator);
lenient().when(storageProvider.createVariablesStorage()).thenReturn(variableStorage);
lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true);
lenient()
.when(worldStateKeyValueStorage.updater())
Expand Down
Expand Up @@ -116,14 +116,16 @@ public void setup() throws JsonProcessingException {
lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions);
lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions);
lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions);
final var variableStorage = new VariablesKeyValueStorage(new InMemoryKeyValueStorage());
lenient()
.when(storageProvider.createBlockchainStorage(any(), any(), any()))
.thenReturn(
new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(),
new VariablesKeyValueStorage(new InMemoryKeyValueStorage()),
variableStorage,
new MainnetBlockHeaderFunctions(),
false));
lenient().when(storageProvider.createVariablesStorage()).thenReturn(variableStorage);
lenient()
.when(
storageProvider.createWorldStateStorageCoordinator(
Expand Down
Expand Up @@ -132,14 +132,16 @@ public void setup() {
when(genesisConfigOptions.getThanosBlockNumber()).thenReturn(OptionalLong.empty());
when(genesisConfigOptions.getTerminalBlockHash()).thenReturn(Optional.of(Hash.ZERO));
lenient().when(genesisConfigOptions.getTerminalBlockNumber()).thenReturn(OptionalLong.of(1L));
final var variableStorage = new VariablesKeyValueStorage(new InMemoryKeyValueStorage());
lenient()
.when(storageProvider.createBlockchainStorage(any(), any(), any()))
.thenReturn(
new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(),
new VariablesKeyValueStorage(new InMemoryKeyValueStorage()),
variableStorage,
new MainnetBlockHeaderFunctions(),
false));
lenient().when(storageProvider.createVariablesStorage()).thenReturn(variableStorage);
lenient()
.when(storageProvider.getStorageBySegmentIdentifier(any()))
.thenReturn(new InMemoryKeyValueStorage());
Expand Down
@@ -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.