diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java index 77c50a07661..48aaf0dd8bf 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java @@ -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; @@ -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 @@ -164,6 +166,7 @@ public Optional getAccount(final Hash accountHash) { composedWorldStateStorage); } + @Override public Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); @@ -246,12 +249,14 @@ public Optional getStorageValueByStorageSlotKey( composedWorldStateStorage); } + @Override public Map streamFlatAccounts( final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return getFlatDbStrategy() .streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max); } + @Override public Map streamFlatStorages( final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return getFlatDbStrategy() @@ -264,6 +269,7 @@ public NavigableMap 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) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java index 77f82914691..8a248d94620 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java @@ -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; @@ -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 nodeAddedListeners = Subscribers.create(); private final KeyValueStorage keyValueStorage; @@ -57,10 +58,17 @@ public Optional getCode(final Bytes32 codeHash) { } } + @Override + public Optional getTrieNodeUnsafe(final Bytes key) { + return getAccountStateTrieNode(Bytes32.wrap(key)); + } + + @Override public Optional getAccountStateTrieNode(final Bytes32 nodeHash) { return getTrieNode(nodeHash); } + @Override public Optional getAccountStorageTrieNode(final Bytes32 nodeHash) { return getTrieNode(nodeHash); } @@ -88,6 +96,7 @@ public Optional getNodeData(final Bytes32 hash) { } } + @Override public boolean isWorldStateAvailable(final Bytes32 rootHash) { return getAccountStateTrieNode(rootHash).isPresent(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java index 4e3d6ceee6b..1ef97972150 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java @@ -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 { @@ -26,6 +30,8 @@ public interface WorldStateKeyValueStorage { void clear(); + Optional getTrieNodeUnsafe(final Bytes key); + interface NodesAddedListener { void onNodesAdded(Collection nodeHash); } @@ -33,4 +39,22 @@ interface NodesAddedListener { interface Updater { void commit(); } + + interface PathBasedWorldStateKeyValueStorage extends WorldStateKeyValueStorage { + boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash); + Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash); + Optional getAccountStorageTrieNode( + final Hash accountHash, final Bytes location, final Bytes32 nodeHash); + Map streamFlatAccounts( + final Bytes startKeyHash, final Bytes32 endKeyHash, final long max); + Map streamFlatStorages( + final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max); + + } + + interface HashBasedWorldStateKeyValueStorage extends WorldStateKeyValueStorage { + boolean isWorldStateAvailable(final Bytes32 rootHash); + Optional getAccountStateTrieNode(final Bytes32 nodeHash); + Optional getAccountStorageTrieNode(final Bytes32 nodeHash); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java index b3abe347f3b..746e81d2a97 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java @@ -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 { + private final T worldStateKeyValueStorage; - public WorldStateStorageCoordinator(final WorldStateKeyValueStorage worldStateKeyValueStorage) { + public WorldStateStorageCoordinator(final T worldStateKeyValueStorage) { this.worldStateKeyValueStorage = worldStateKeyValueStorage; } @@ -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 getTrieNodeUnsafe(final Bytes key) { - return applyForStrategy( - bonsai -> bonsai.getTrieNodeUnsafe(key), - forest -> forest.getAccountStateTrieNode(Bytes32.wrap(key))); + return worldStateKeyValueStorage.getTrieNodeUnsafe(key); } public Optional 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 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") @@ -109,24 +124,9 @@ public void applyOnMatchingStrategy( } } - public RESPONSE applyForStrategy( - final Function onBonsai, - final Function onForest) { - if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { - return onBonsai.apply(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage())); - } else { - return onForest.apply(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage())); - } - } - public void consumeForStrategy( - final Consumer onBonsai, - final Consumer onForest) { - if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { - onBonsai.accept(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage())); - } else { - onForest.accept(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage())); - } + final Consumer consumer) { + consumer.accept(worldStateKeyValueStorage()); } public static void applyForStrategy( @@ -148,7 +148,7 @@ public void clear() { worldStateKeyValueStorage.clear(); } - public WorldStateKeyValueStorage worldStateKeyValueStorage() { + public T worldStateKeyValueStorage() { return worldStateKeyValueStorage; } }