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

stem based flat db for verkle #7778

Merged
merged 19 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2756,7 +2756,6 @@ private String generateConfigurationOverview() {
if (rocksDBPlugin.isHighSpecEnabled()) {
builder.setHighSpecEnabled();
}

if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getDiffBasedSubStorageConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
private DiffBasedSubStorageOptions diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.create();

/** Options specific to verkle storage modes. */
@Mixin private VerkleSubStorageOptions verkleSubStorageOptions = VerkleSubStorageOptions.create();

/** Default Constructor. */
DataStorageOptions() {}

Expand All @@ -76,6 +79,7 @@ public static DataStorageOptions create() {
*/
public void validate(final CommandLine commandLine) {
diffBasedSubStorageOptions.validate(commandLine, dataStorageFormat);
verkleSubStorageOptions.validate(commandLine, dataStorageFormat);
Copy link
Contributor

@lu-pinto lu-pinto Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you call validate? It's a noop, not even part of an interface or abstract

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just to ensure that all the logic is coded in the same way so that if tomorrow someone adds a flag that requires a check, they don’t have to wonder why it doesn’t work or how to do it. They just need to follow the same approach as in other parts of the code and simply implement the check in validate. But if you think it's better to remove why not

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no strong opinions, you can leave it

}

/**
Expand All @@ -90,6 +94,8 @@ public static DataStorageOptions fromConfig(final DataStorageConfiguration domai
dataStorageOptions.receiptCompactionEnabled = domainObject.getReceiptCompactionEnabled();
dataStorageOptions.diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.fromConfig(domainObject.getDiffBasedSubStorageConfiguration());
dataStorageOptions.verkleSubStorageOptions =
VerkleSubStorageOptions.fromConfig(domainObject.getVerkleSubStorageConfiguration());
return dataStorageOptions;
}

Expand All @@ -99,14 +105,16 @@ public DataStorageConfiguration toDomainObject() {
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(dataStorageFormat)
.receiptCompactionEnabled(receiptCompactionEnabled)
.diffBasedSubStorageConfiguration(diffBasedSubStorageOptions.toDomainObject());
.diffBasedSubStorageConfiguration(diffBasedSubStorageOptions.toDomainObject())
.verkleSubStorageConfiguration(verkleSubStorageOptions.toDomainObject());
return builder.build();
}

@Override
public List<String> getCLIOptions() {
final List<String> cliOptions = CommandLineUtils.getCLIOptions(this, new DataStorageOptions());
cliOptions.addAll(diffBasedSubStorageOptions.getCLIOptions());
cliOptions.addAll(verkleSubStorageOptions.getCLIOptions());
return cliOptions;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ public static DiffBasedSubStorageOptions create() {
* to apply.
*/
public void validate(final CommandLine commandLine, final DataStorageFormat dataStorageFormat) {
if (DataStorageFormat.BONSAI == dataStorageFormat) {
if (DataStorageFormat.BONSAI == dataStorageFormat
|| DataStorageFormat.VERKLE == dataStorageFormat) {
if (limitTrieLogsEnabled) {
if (maxLayersToLoad < MINIMUM_TRIE_LOG_RETENTION_LIMIT) {
throw new CommandLine.ParameterException(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.storage;

import static org.hyperledger.besu.ethereum.worldstate.VerkleSubStorageConfiguration.VerkleUnstable.DEFAULT_STEM_FLAT_DB_ENABLED;

import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.ImmutableVerkleSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.VerkleSubStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;

import java.util.List;

import picocli.CommandLine;
import picocli.CommandLine.Option;

/** The Data storage CLI options. */
public class VerkleSubStorageOptions implements CLIOptions<VerkleSubStorageConfiguration> {

@CommandLine.ArgGroup(validate = false)
private final VerkleSubStorageOptions.Unstable unstableOptions = new Unstable();

/** Default Constructor. */
VerkleSubStorageOptions() {}

/** The unstable options for data storage. */
public static class Unstable {

@Option(
hidden = true,
names = {
"--Xverkle-stem-flat-db-enabled",
},
arity = "1",
description = "Enables stem flat database strategy for verkle. (default: ${DEFAULT-VALUE})")
private Boolean stemFlatDbEnabled = DEFAULT_STEM_FLAT_DB_ENABLED;

/** Default Constructor. */
Unstable() {}
}

/**
* Create data storage options.
*
* @return the data storage options
*/
public static VerkleSubStorageOptions create() {
return new VerkleSubStorageOptions();
}

/**
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
* @param dataStorageFormat the selected data storage format which determines the validation rules
* to apply.
*/
public void validate(final CommandLine commandLine, final DataStorageFormat dataStorageFormat) {
// no op
}

/**
* Converts to options from the configuration
*
* @param domainObject to be reversed
* @return the options that correspond to the configuration
*/
public static VerkleSubStorageOptions fromConfig(
final VerkleSubStorageConfiguration domainObject) {
final VerkleSubStorageOptions dataStorageOptions = VerkleSubStorageOptions.create();
dataStorageOptions.unstableOptions.stemFlatDbEnabled =
domainObject.getUnstable().getStemFlatDbEnabled();
return dataStorageOptions;
}

@Override
public final VerkleSubStorageConfiguration toDomainObject() {
return ImmutableVerkleSubStorageConfiguration.builder()
.unstable(
ImmutableVerkleSubStorageConfiguration.VerkleUnstable.builder()
.stemFlatDbEnabled(unstableOptions.stemFlatDbEnabled)
.build())
.build();
}

@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new VerkleSubStorageOptions());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.BonsaiTrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
Expand Down Expand Up @@ -386,7 +386,8 @@ IdentityHashMap<byte[], byte[]> readTrieLogsAsRlpFromFile(final String batchFile
while (!input.isEndOfCurrentList()) {
final Bytes trieLogBytes = input.currentListAsBytes();
TrieLogLayer trieLogLayer =
TrieLogFactoryImpl.readFrom(new BytesValueRLPInput(Bytes.wrap(trieLogBytes), false));
BonsaiTrieLogFactoryImpl.readFrom(
new BytesValueRLPInput(Bytes.wrap(trieLogBytes), false));
trieLogs.put(trieLogLayer.getBlockHash().toArrayUnsafe(), trieLogBytes.toArrayUnsafe());
}
input.leaveList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.BonsaiTrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
Expand Down Expand Up @@ -118,7 +118,7 @@ private static byte[] createTrieLog(final BlockHeader blockHeader) {
TrieLogLayer trieLogLayer = new TrieLogLayer();
trieLogLayer.setBlockHash(blockHeader.getBlockHash());
final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput();
TrieLogFactoryImpl.writeTo(trieLogLayer, rlpLog);
BonsaiTrieLogFactoryImpl.writeTo(trieLogLayer, rlpLog);
return rlpLog.encoded().toArrayUnsafe();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ public BlockProcessingResult validateBlock(final Block block) {
HeaderValidationMode.FULL,
HeaderValidationMode.NONE,
false);

return validationResult;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import org.hyperledger.besu.ethereum.rlp.RLPOutput;

import java.util.Optional;

/** The values of an account in the world state trie. */
public interface AccountValue {
/**
Expand Down Expand Up @@ -46,6 +48,13 @@ public interface AccountValue {
*/
Hash getCodeHash();

/**
* The size of the EVM bytecode associated with this account.
*
* @return the size of the account code (which may be {@link Optional#empty()}).
*/
Optional<Long> getCodeSize();

/**
* Writes the account value to the provided {@link RLPOutput}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.cache.preloader.StemPreloader;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.storage.VerkleWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
Expand Down Expand Up @@ -86,7 +87,8 @@ public WorldStateKeyValueStorage createWorldStateStorage(
if (dataStorageConfiguration.getDataStorageFormat().equals(DataStorageFormat.BONSAI)) {
return new BonsaiWorldStateKeyValueStorage(this, metricsSystem, dataStorageConfiguration);
} else if (dataStorageConfiguration.getDataStorageFormat().equals(DataStorageFormat.VERKLE)) {
return new VerkleWorldStateKeyValueStorage(this, metricsSystem);
return new VerkleWorldStateKeyValueStorage(
this, new StemPreloader(), dataStorageConfiguration, metricsSystem);
} else {
return new ForestWorldStateKeyValueStorage(
getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.WORLD_STATE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;

import java.util.Optional;

/** Represents the raw values associated with an account in the world state trie. */
public abstract class AbstractStateTrieAccountValue implements AccountValue {

Expand Down Expand Up @@ -76,6 +78,14 @@ public Hash getStorageRoot() {
return Hash.EMPTY_TRIE_HASH;
}

/**
* The size of the EVM bytecode associated with this account.
*
* @return the size of the account code (which may be {@link Optional#empty()}).
*/
@Override
public abstract Optional<Long> getCodeSize();

@Override
public abstract void writeTo(final RLPOutput out);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.NoOpTrieLogManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.cache.VerkleNoOpCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.cache.preloader.StemPreloader;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.storage.VerkleWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.worldview.VerkleWorldState;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
Expand Down Expand Up @@ -52,7 +53,7 @@ public static MutableWorldState createGenesisWorldState(
return createGenesisBonsaiWorldState();
} else if (Objects.requireNonNull(dataStorageConfiguration).getDataStorageFormat()
== DataStorageFormat.VERKLE) {
return createGenesisVerkleWorldState();
return createGenesisVerkleWorldState(dataStorageConfiguration);
} else {
return createGenesisForestWorldState();
}
Expand Down Expand Up @@ -83,13 +84,16 @@ private static MutableWorldState createGenesisBonsaiWorldState() {
new DiffBasedWorldStateConfig());
}

private static MutableWorldState createGenesisVerkleWorldState() {
private static MutableWorldState createGenesisVerkleWorldState(
final DataStorageConfiguration dataStorageConfiguration) {
final VerkleWorldStateKeyValueStorage verkleWorldStateKeyValueStorage =
new VerkleWorldStateKeyValueStorage(
new KeyValueStorageProvider(
segmentIdentifiers -> new SegmentedInMemoryKeyValueStorage(),
new InMemoryKeyValueStorage(),
new NoOpMetricsSystem()),
new StemPreloader(),
dataStorageConfiguration,
new NoOpMetricsSystem());
return new VerkleWorldState(
verkleWorldStateKeyValueStorage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hyperledger.besu.ethereum.rlp.RLPOutput;

import java.util.Objects;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes32;

Expand All @@ -49,6 +50,12 @@ public Hash getStorageRoot() {
return storageRoot;
}

@Override
public Optional<Long> getCodeSize() {
throw new UnsupportedOperationException(
"Retrieving code size from state trie account value is not possible with Patricia Merkle Trie");
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public Hash getStorageRoot() {
*
* @return the size of the account code (which may be {@link Optional#empty()}).
*/
@Override
public Optional<Long> getCodeSize() {
return codeSize;
}
Expand All @@ -70,19 +71,17 @@ public int hashCode() {
@Override
public void writeTo(final RLPOutput out) {
out.startList();

out.writeUInt256Scalar(balance);
out.writeLongScalar(nonce);
out.writeUInt256Scalar(balance);
out.writeBytes(codeHash);
codeSize.ifPresent(out::writeLongScalar);
out.endList();
}

public static VerkleStateTrieAccountValue readFrom(final RLPInput in) {
in.enterList();

final Wei balance = Wei.of(in.readUInt256Scalar());
final long nonce = in.readLongScalar();
final Wei balance = Wei.of(in.readUInt256Scalar());
Bytes32 codeHash;
final Optional<Long> codeSize;
if (in.nextIsNull()) {
Expand Down
Loading
Loading