Skip to content

Commit

Permalink
proposed worldstate key value storage abstraction
Browse files Browse the repository at this point in the history
Signed-off-by: garyschulte <[email protected]>
  • Loading branch information
garyschulte committed Jan 17, 2024
1 parent 9f4cd99 commit aab6187
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage.PathBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
Expand All @@ -53,7 +54,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorage, AutoCloseable {
public class BonsaiWorldStateKeyValueStorage implements
PathBasedWorldStateKeyValueStorage, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class);

// 0x776f726c64526f6f74
Expand Down Expand Up @@ -164,6 +166,7 @@ public Optional<Bytes> getAccount(final Hash accountHash) {
composedWorldStateStorage);
}

@Override
public Optional<Bytes> getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) {
if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) {
return Optional.of(MerkleTrie.EMPTY_TRIE_NODE);
Expand Down Expand Up @@ -246,12 +249,14 @@ public Optional<Bytes> getStorageValueByStorageSlotKey(
composedWorldStateStorage);
}

@Override
public Map<Bytes32, Bytes> streamFlatAccounts(
final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbStrategy()
.streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max);
}

@Override
public Map<Bytes32, Bytes> streamFlatStorages(
final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbStrategy()
Expand All @@ -264,6 +269,7 @@ public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
throw new RuntimeException("Bonsai Tries does not currently support enumerating storage");
}

@Override
public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage.HashBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.util.Subscribers;
Expand All @@ -34,7 +35,7 @@
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;

public class ForestWorldStateKeyValueStorage implements WorldStateKeyValueStorage {
public class ForestWorldStateKeyValueStorage implements HashBasedWorldStateKeyValueStorage {

private final Subscribers<NodesAddedListener> nodeAddedListeners = Subscribers.create();
private final KeyValueStorage keyValueStorage;
Expand All @@ -57,10 +58,17 @@ public Optional<Bytes> getCode(final Bytes32 codeHash) {
}
}

@Override
public Optional<Bytes> getTrieNodeUnsafe(final Bytes key) {
return getAccountStateTrieNode(Bytes32.wrap(key));
}

@Override
public Optional<Bytes> getAccountStateTrieNode(final Bytes32 nodeHash) {
return getTrieNode(nodeHash);
}

@Override
public Optional<Bytes> getAccountStorageTrieNode(final Bytes32 nodeHash) {
return getTrieNode(nodeHash);
}
Expand Down Expand Up @@ -88,6 +96,7 @@ public Optional<Bytes> getNodeData(final Bytes32 hash) {
}
}

@Override
public boolean isWorldStateAvailable(final Bytes32 rootHash) {
return getAccountStateTrieNode(rootHash).isPresent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
package org.hyperledger.besu.ethereum.worldstate;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.datatypes.Hash;

public interface WorldStateKeyValueStorage {

Expand All @@ -26,11 +30,31 @@ public interface WorldStateKeyValueStorage {

void clear();

Optional<Bytes> getTrieNodeUnsafe(final Bytes key);

interface NodesAddedListener {
void onNodesAdded(Collection<Bytes32> nodeHash);
}

interface Updater {
void commit();
}

interface PathBasedWorldStateKeyValueStorage extends WorldStateKeyValueStorage {
boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash);
Optional<Bytes> getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash);
Optional<Bytes> getAccountStorageTrieNode(
final Hash accountHash, final Bytes location, final Bytes32 nodeHash);
Map<Bytes32, Bytes> streamFlatAccounts(
final Bytes startKeyHash, final Bytes32 endKeyHash, final long max);
Map<Bytes32, Bytes> streamFlatStorages(
final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max);

}

interface HashBasedWorldStateKeyValueStorage extends WorldStateKeyValueStorage {
boolean isWorldStateAvailable(final Bytes32 rootHash);
Optional<Bytes> getAccountStateTrieNode(final Bytes32 nodeHash);
Optional<Bytes> getAccountStorageTrieNode(final Bytes32 nodeHash);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage.HashBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage.PathBasedWorldStateKeyValueStorage;

public class WorldStateStorageCoordinator {
private final WorldStateKeyValueStorage worldStateKeyValueStorage;
public class WorldStateStorageCoordinator<T extends WorldStateKeyValueStorage> {
private final T worldStateKeyValueStorage;

public WorldStateStorageCoordinator(final WorldStateKeyValueStorage worldStateKeyValueStorage) {
public WorldStateStorageCoordinator(final T worldStateKeyValueStorage) {
this.worldStateKeyValueStorage = worldStateKeyValueStorage;
}

Expand All @@ -37,28 +39,41 @@ public DataStorageFormat getDataStorageFormat() {
}

public boolean isWorldStateAvailable(final Bytes32 nodeHash, final Hash blockHash) {
return applyForStrategy(
bonsai -> bonsai.isWorldStateAvailable(nodeHash, blockHash),
forest -> forest.isWorldStateAvailable(nodeHash));
if (worldStateKeyValueStorage instanceof PathBasedWorldStateKeyValueStorage bonsai) {
return bonsai.isWorldStateAvailable(nodeHash, blockHash);
} else {
if (worldStateKeyValueStorage instanceof HashBasedWorldStateKeyValueStorage forest) {
return forest.isWorldStateAvailable(nodeHash);
}
}
throw new UnsupportedOperationException("Storage implementation does not implement isWorldStateAvailable");
}

public Optional<Bytes> getTrieNodeUnsafe(final Bytes key) {
return applyForStrategy(
bonsai -> bonsai.getTrieNodeUnsafe(key),
forest -> forest.getAccountStateTrieNode(Bytes32.wrap(key)));
return worldStateKeyValueStorage.getTrieNodeUnsafe(key);
}

public Optional<Bytes> getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) {
return applyForStrategy(
bonsai -> bonsai.getAccountStateTrieNode(location, nodeHash),
forest -> forest.getAccountStateTrieNode(nodeHash));
if (worldStateKeyValueStorage instanceof PathBasedWorldStateKeyValueStorage bonsai) {
return bonsai.getAccountStateTrieNode(location, nodeHash);
} else {
if (worldStateKeyValueStorage instanceof HashBasedWorldStateKeyValueStorage forest) {
return forest.getAccountStateTrieNode(nodeHash);
}
}
throw new UnsupportedOperationException("Storage implementation does not implement isWorldStateAvailable");
}

public Optional<Bytes> getAccountStorageTrieNode(
final Hash accountHash, final Bytes location, final Bytes32 nodeHash) {
return applyForStrategy(
bonsai -> bonsai.getAccountStorageTrieNode(accountHash, location, nodeHash),
forest -> forest.getAccountStorageTrieNode(nodeHash));
if (worldStateKeyValueStorage instanceof PathBasedWorldStateKeyValueStorage bonsai) {
return bonsai.getAccountStorageTrieNode(accountHash, location, nodeHash);
} else {
if (worldStateKeyValueStorage instanceof HashBasedWorldStateKeyValueStorage forest) {
return forest.getAccountStorageTrieNode(nodeHash);
}
}
throw new UnsupportedOperationException("Storage implementation does not implement isWorldStateAvailable");
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -109,24 +124,9 @@ public void applyOnMatchingStrategy(
}
}

public <RESPONSE> RESPONSE applyForStrategy(
final Function<BonsaiWorldStateKeyValueStorage, RESPONSE> onBonsai,
final Function<ForestWorldStateKeyValueStorage, RESPONSE> onForest) {
if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) {
return onBonsai.apply(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage()));
} else {
return onForest.apply(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage()));
}
}

public void consumeForStrategy(
final Consumer<BonsaiWorldStateKeyValueStorage> onBonsai,
final Consumer<ForestWorldStateKeyValueStorage> onForest) {
if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) {
onBonsai.accept(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage()));
} else {
onForest.accept(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage()));
}
final Consumer<T> consumer) {
consumer.accept(worldStateKeyValueStorage());
}

public static void applyForStrategy(
Expand All @@ -148,7 +148,7 @@ public void clear() {
worldStateKeyValueStorage.clear();
}

public WorldStateKeyValueStorage worldStateKeyValueStorage() {
public T worldStateKeyValueStorage() {
return worldStateKeyValueStorage;
}
}

0 comments on commit aab6187

Please sign in to comment.