diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStatePreimageKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStatePreimageKeyValueStorage.java
index 51a72bf760..b312e23c0c 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStatePreimageKeyValueStorage.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/WorldStatePreimageKeyValueStorage.java
@@ -25,16 +25,6 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
-/**
- * This store is used in Forest storage format, and expects to use an Updater to insert and commit
- * changes to storage, adjacent to worldstate commits. By not being part of the worldstate
- * transaction and commit data in this implementation can become out-of-sync (by failing to commit
- * preimages by hash) on abnormal exits of besu.
- *
- *
This implementation remains here for the deprecated forest storage format, and should be
- * retired along with Forest.
- */
-@Deprecated
public class WorldStatePreimageKeyValueStorage implements WorldStatePreimageStorage {
private final KeyValueStorage keyValueStorage;
@@ -59,6 +49,11 @@ public class WorldStatePreimageKeyValueStorage implements WorldStatePreimageStor
.map(val -> Address.wrap(Bytes.wrap(val)));
}
+ @Override
+ public boolean canSupportStreaming() {
+ return keyValueStorage.isPersistent();
+ }
+
@Override
public Updater updater() {
return new Updater(keyValueStorage.startTransaction());
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java
index 2437118d64..c03487b7cb 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java
@@ -44,7 +44,10 @@ public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKey
final SnappedKeyValueStorage segmentedWorldStateStorage,
final KeyValueStorage trieLogStorage) {
super(
- parentWorldStateStorage.flatDbStrategyProvider, segmentedWorldStateStorage, trieLogStorage);
+ parentWorldStateStorage.flatDbStrategyProvider,
+ segmentedWorldStateStorage,
+ trieLogStorage,
+ parentWorldStateStorage.getPreimageStorage());
this.parentWorldStateStorage = parentWorldStateStorage;
this.subscribeParentId = parentWorldStateStorage.subscribe(this);
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
index 159b626f9e..3dd048cd74 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
@@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
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.WorldStatePreimageStorage;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
@@ -58,7 +59,8 @@ public class BonsaiWorldStateKeyValueStorage extends DiffBasedWorldStateKeyValue
provider.getStorageBySegmentIdentifiers(
List.of(
ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE)),
- provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE));
+ provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE),
+ provider.createWorldStatePreimageStorage());
this.flatDbStrategyProvider =
new BonsaiFlatDbStrategyProvider(metricsSystem, dataStorageConfiguration);
flatDbStrategyProvider.loadFlatDbStrategy(composedWorldStateStorage);
@@ -67,8 +69,9 @@ public class BonsaiWorldStateKeyValueStorage extends DiffBasedWorldStateKeyValue
public BonsaiWorldStateKeyValueStorage(
final BonsaiFlatDbStrategyProvider flatDbStrategyProvider,
final SegmentedKeyValueStorage composedWorldStateStorage,
- final KeyValueStorage trieLogStorage) {
- super(composedWorldStateStorage, trieLogStorage);
+ final KeyValueStorage trieLogStorage,
+ final WorldStatePreimageStorage preimageStorage) {
+ super(composedWorldStateStorage, trieLogStorage, preimageStorage);
this.flatDbStrategyProvider = flatDbStrategyProvider;
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/CachingPreImageStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/CachingPreImageStorage.java
deleted file mode 100644
index f5cc73e4d7..0000000000
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/CachingPreImageStorage.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.ethereum.trie.diffbased.bonsai.storage;
-
-import org.hyperledger.besu.datatypes.Address;
-import org.hyperledger.besu.datatypes.Hash;
-
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import org.apache.tuweni.bytes.Bytes;
-import org.apache.tuweni.bytes.Bytes32;
-import org.apache.tuweni.units.bigints.UInt256;
-
-/** Acts as both a Hasher and PreImageStorage for Bonsai storage format. */
-public interface CachingPreImageStorage {
-
- enum HashSource {
- ACCOUNT_ADDRESS((byte) 0x00),
- SLOT_KEY((byte) 0x01);
- byte internal_type;
-
- HashSource(final byte type) {
- internal_type = type;
- }
-
- byte getTypeSuffix() {
- return internal_type;
- }
-
- static HashSource wrap(final byte val) {
- if (val == 0x00) {
- return ACCOUNT_ADDRESS;
- } else if (val == 0x01) {
- return SLOT_KEY;
- } else {
- throw new NoSuchElementException(String.format("Value %x is not a preimage source", val));
- }
- }
- }
-
- record HashKey(Hash hashValue, HashSource source) {}
-
- /**
- * If this value is not already present, save in preImage store and return the hash value.
- *
- * @param value value to hash
- * @return Hash of value
- */
- Hash hashAndSaveAddressPreImage(final Bytes value);
-
- Hash hashAndSaveSlotKeyPreImage(final UInt256 keyUInt);
-
- Stream
streamAddressPreImages(final Bytes32 startKeyHash, final int limit);
-
- Optional getStorageTrieKeyPreimage(final Bytes32 trieKey);
-
- Optional getAccountTrieKeyPreimage(final Bytes32 trieKey);
-
- Optional getRawHashPreImage(final Hash hash);
-
- /**
- * This method indicates whether this Pre-Image store is "complete", meaning it has all of the
- * hash preimages for all entries in the state trie.
- *
- * @return boolean indicating whether the pre-image store is complete or not
- */
- default boolean canSupportStreaming() {
- return false;
- }
-
- /**
- * A caching PreImageProxy suitable for ReferenceTestWorldState which saves hashes in an unbounded
- * BiMap.
- */
- class UnboundedPreImageStorage implements CachingPreImageStorage {
- BiMap preImageCache = HashBiMap.create();
-
- @Override
- public Hash hashAndSaveAddressPreImage(final Bytes value) {
- return preImageCache
- .inverse()
- .computeIfAbsent(
- value, v -> new HashKey(Address.wrap(v).addressHash(), HashSource.ACCOUNT_ADDRESS))
- .hashValue();
- }
-
- @Override
- public Hash hashAndSaveSlotKeyPreImage(final UInt256 value) {
- return preImageCache
- .inverse()
- .computeIfAbsent(value, v -> new HashKey(Hash.hash(v), HashSource.SLOT_KEY))
- .hashValue();
- }
-
- @Override
- public Stream streamAddressPreImages(final Bytes32 startKeyHash, final int limit) {
- final Hash startHash = Hash.wrap(startKeyHash);
- return preImageCache.entrySet().stream()
- .filter(entry -> entry.getKey().source() == HashSource.ACCOUNT_ADDRESS)
- .filter(entry -> entry.getKey().hashValue().compareTo(startHash) >= 0)
- .map(e -> Address.wrap(e.getValue()))
- .limit(limit);
- }
-
- @Override
- public Optional getStorageTrieKeyPreimage(final Bytes32 trieKey) {
- return Optional.ofNullable(
- preImageCache.get(new HashKey(Hash.wrap(trieKey), HashSource.SLOT_KEY)))
- .map(UInt256::fromBytes);
- }
-
- @Override
- public Optional getAccountTrieKeyPreimage(final Bytes32 trieKey) {
- return Optional.ofNullable(
- preImageCache.get(new HashKey(Hash.wrap(trieKey), HashSource.ACCOUNT_ADDRESS)))
- .map(Address::wrap);
- }
-
- @Override
- public Optional getRawHashPreImage(final Hash hash) {
- return Stream.of(
- preImageCache.get(new HashKey(hash, HashSource.ACCOUNT_ADDRESS)),
- preImageCache.get(new HashKey(hash, HashSource.SLOT_KEY)))
- .filter(Objects::nonNull)
- .findAny();
- }
-
- @Override
- public boolean canSupportStreaming() {
- return true;
- }
- }
-
- class CachingOnlyPreImageStorage implements CachingPreImageStorage {
-
- // TODO: config max size perhaps
- private static final Cache preimageCache =
- Caffeine.newBuilder().maximumSize(10000).build();
-
- @Override
- public Hash hashAndSaveAddressPreImage(final Bytes value) {
- // defer to the static Address hash map used by the evm
- return preimageCache.get(value, v -> Address.wrap(value).addressHash());
- }
-
- @Override
- public Hash hashAndSaveSlotKeyPreImage(final UInt256 keyUInt) {
- return preimageCache.get(keyUInt, Hash::hash);
- }
-
- @Override
- public Stream streamAddressPreImages(final Bytes32 startKeyHash, final int limit) {
- // not configured for preimage streaming
- return Stream.empty();
- }
-
- @Override
- public Optional getStorageTrieKeyPreimage(final Bytes32 trieKey) {
- return getRawHashPreImage(Hash.wrap(trieKey)).map(UInt256::fromBytes);
- }
-
- @Override
- public Optional getAccountTrieKeyPreimage(final Bytes32 trieKey) {
- return getRawHashPreImage(Hash.wrap(trieKey)).map(Address::wrap);
- }
-
- @Override
- public Optional getRawHashPreImage(final Hash hash) {
- return preimageCache.asMap().entrySet().stream()
- .filter(e -> e.getValue().equals(hash))
- .findFirst()
- .map(Map.Entry::getKey);
- }
- }
-}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java
index d43f585b45..c1d32e14ab 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java
@@ -187,22 +187,19 @@ public class BonsaiWorldState extends DiffBasedWorldState {
final MerkleTrie accountTrie) {
for (final Map.Entry> accountUpdate :
worldStateUpdater.getAccountsToUpdate().entrySet()) {
- final Bytes accountKey = accountUpdate.getKey();
+ final Address accountKey = accountUpdate.getKey();
final DiffBasedValue bonsaiValue = accountUpdate.getValue();
final BonsaiAccount updatedAccount = bonsaiValue.getUpdated();
try {
if (updatedAccount == null) {
- final Hash addressHash = getPreImageProxy().hashAndSaveAddressPreImage(accountKey);
- accountTrie.remove(addressHash);
+ accountTrie.remove(accountKey.addressHash());
maybeStateUpdater.ifPresent(
- bonsaiUpdater -> bonsaiUpdater.removeAccountInfoState(addressHash));
+ bonsaiUpdater -> bonsaiUpdater.removeAccountInfoState(accountKey.addressHash()));
} else {
final Hash addressHash = updatedAccount.getAddressHash();
final Bytes accountValue = updatedAccount.serializeAccount();
maybeStateUpdater.ifPresent(
- bonsaiUpdater ->
- bonsaiUpdater.putAccountInfoState(
- getPreImageProxy().hashAndSaveAddressPreImage(accountKey), accountValue));
+ bonsaiUpdater -> bonsaiUpdater.putAccountInfoState(addressHash, accountValue));
accountTrie.put(addressHash, accountValue);
}
} catch (MerkleTrieException e) {
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java
index 75b370c1cd..e401c244ac 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java
@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWo
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
+import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.BesuContext;
@@ -51,6 +52,7 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive {
protected final Blockchain blockchain;
protected final TrieLogManager trieLogManager;
+ protected final WorldStatePreimageStorage preimageStorage;
protected DiffBasedCachedWorldStorageManager cachedWorldStorageManager;
protected DiffBasedWorldState persistedState;
@@ -71,6 +73,7 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive {
worldStateKeyValueStorage,
maxLayersToLoad.orElse(DiffBasedCachedWorldStorageManager.RETAINED_LAYERS),
pluginContext);
+ this.preimageStorage = worldStateKeyValueStorage.getPreimageStorage();
this.blockchain = blockchain;
this.defaultWorldStateConfig = new DiffBasedWorldStateConfig();
}
@@ -85,6 +88,7 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive {
this.trieLogManager = trieLogManager;
this.blockchain = blockchain;
this.defaultWorldStateConfig = new DiffBasedWorldStateConfig();
+ preimageStorage = worldStateKeyValueStorage.getPreimageStorage();
}
protected void provideCachedWorldStorageManager(
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java
index 4043089fc6..eb94eadc05 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java
@@ -24,12 +24,12 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
-import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.CachingPreImageStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
+import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
@@ -64,10 +64,7 @@ public abstract class DiffBasedWorldStateKeyValueStorage
private static final Logger LOG =
LoggerFactory.getLogger(DiffBasedWorldStateKeyValueStorage.class);
- // TODO: config this based on dataStorageConfiguration, use real storage where appropriate
- // currently hard-coded to Unbounded preimage store so ref/spec tests pass
- private static final CachingPreImageStorage preImageProxy =
- new CachingPreImageStorage.UnboundedPreImageStorage();
+ private final WorldStatePreimageStorage preImageProxy;
// 0x776f726c64526f6f74
public static final byte[] WORLD_ROOT_HASH_KEY = "worldRoot".getBytes(StandardCharsets.UTF_8);
@@ -90,13 +87,16 @@ public abstract class DiffBasedWorldStateKeyValueStorage
ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE));
this.trieLogStorage =
provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE);
+ this.preImageProxy = provider.createWorldStatePreimageStorage();
}
public DiffBasedWorldStateKeyValueStorage(
final SegmentedKeyValueStorage composedWorldStateStorage,
- final KeyValueStorage trieLogStorage) {
+ final KeyValueStorage trieLogStorage,
+ final WorldStatePreimageStorage preImageStorage) {
this.composedWorldStateStorage = composedWorldStateStorage;
this.trieLogStorage = trieLogStorage;
+ this.preImageProxy = preImageStorage;
}
public abstract FlatDbMode getFlatDbMode();
@@ -110,14 +110,14 @@ public abstract class DiffBasedWorldStateKeyValueStorage
return composedWorldStateStorage;
}
- public CachingPreImageStorage getPreImageProxy() {
- return preImageProxy;
- }
-
public KeyValueStorage getTrieLogStorage() {
return trieLogStorage;
}
+ public WorldStatePreimageStorage getPreimageStorage() {
+ return preImageProxy;
+ }
+
public Optional getTrieLog(final Hash blockHash) {
return trieLogStorage.get(blockHash.toArrayUnsafe());
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/NoOpTrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/NoOpTrieLogManager.java
index 8c8c2acbfc..edea97f4e9 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/NoOpTrieLogManager.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/NoOpTrieLogManager.java
@@ -29,7 +29,7 @@ public class NoOpTrieLogManager extends TrieLogManager {
}
@Override
- public synchronized void saveTrieLog(
+ public synchronized Optional saveTrieLog(
final DiffBasedWorldStateUpdateAccumulator> localUpdater,
final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader,
@@ -37,6 +37,7 @@ public class NoOpTrieLogManager extends TrieLogManager {
// notify trie log added observers, synchronously
TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader);
trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog)));
+ return Optional.of(trieLog);
}
@Override
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java
index 70d45f546d..04e12867a0 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java
@@ -60,7 +60,7 @@ public class TrieLogManager {
this.trieLogFactory = setupTrieLogFactory(pluginContext);
}
- public synchronized void saveTrieLog(
+ public synchronized Optional saveTrieLog(
final DiffBasedWorldStateUpdateAccumulator> localUpdater,
final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader,
@@ -80,6 +80,7 @@ public class TrieLogManager {
trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog)));
success = true;
+ return Optional.of(trieLog);
} finally {
if (success) {
stateUpdater.commit();
@@ -88,6 +89,7 @@ public class TrieLogManager {
}
}
}
+ return Optional.empty();
}
private TrieLog prepareTrieLog(
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java
index 5eacb87f77..46c226afa9 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java
@@ -23,7 +23,6 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
-import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.CachingPreImageStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedLayeredWorldStateKeyValueStorage;
@@ -118,11 +117,6 @@ public abstract class DiffBasedWorldState
return !(worldStateKeyValueStorage instanceof DiffBasedSnapshotWorldStateKeyValueStorage);
}
- @Override
- public CachingPreImageStorage getPreImageProxy() {
- return worldStateKeyValueStorage.getPreImageProxy();
- }
-
/**
* Reset the worldState to this block header
*
@@ -166,7 +160,6 @@ public abstract class DiffBasedWorldState
final DiffBasedWorldStateKeyValueStorage.Updater stateUpdater =
worldStateKeyValueStorage.updater();
Runnable saveTrieLog = () -> {};
-
try {
final Hash calculatedRootHash;
@@ -190,11 +183,40 @@ public abstract class DiffBasedWorldState
verifyWorldStateRoot(calculatedRootHash, blockHeader);
saveTrieLog =
() -> {
- trieLogManager.saveTrieLog(localCopy, calculatedRootHash, blockHeader, this);
+ var trieLog =
+ trieLogManager.saveTrieLog(localCopy, calculatedRootHash, blockHeader, this);
// not save a frozen state in the cache
if (!worldStateConfig.isFrozen()) {
cachedWorldStorageManager.addCachedLayer(blockHeader, calculatedRootHash, this);
}
+
+ // TODO: maybe move this, make conditional so we don't affect performance
+ // if we are not tracking preimages. using the trielog probably is going to get us
+ // duplicates
+ // because we will get updates in addition to creates :frown:
+ if (trieLog.isPresent()) {
+ var log = trieLog.get();
+ var preImageUpdater = worldStateKeyValueStorage.getPreimageStorage().updater();
+ log.getAccountChanges()
+ .keySet()
+ .forEach(
+ acct ->
+ preImageUpdater.putAccountTrieKeyPreimage(acct.addressHash(), acct));
+ localCopy.getStorageToUpdate().values().stream()
+ .flatMap(z -> z.keySet().stream())
+ .filter(
+ z -> {
+ // TODO: we should add logic here to prevent writing
+ // common slot keys
+ return z.getSlotKey().isPresent();
+ })
+ .distinct()
+ .forEach(
+ slot -> {
+ preImageUpdater.putStorageTrieKeyPreimage(
+ slot.getSlotHash(), slot.getSlotKey().get());
+ });
+ }
};
stateUpdater
@@ -304,12 +326,6 @@ public abstract class DiffBasedWorldState
public abstract Stream streamAccounts(
final Bytes32 startKeyHash, final int limit);
- // {
- // return preImageProxy
- // .streamAddressPreImages(startKeyHash, limit)
- // .map(address -> new StreamableAccount(Optional.of(address), get(address)));
- // }
-
@Override
public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) {
return getStorageValue(address, storageKey);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldView.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldView.java
index 49d72c6a11..7ecc49e286 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldView.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldView.java
@@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
-import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.CachingPreImageStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.evm.worldstate.WorldView;
@@ -58,9 +57,6 @@ public interface DiffBasedWorldView extends WorldView {
boolean isPersisted();
- // TODO: comments and naming
- CachingPreImageStorage getPreImageProxy();
-
DiffBasedWorldStateKeyValueStorage getWorldStateStorage();
WorldUpdater updater();
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java
index efa9002f7a..266bfcb50a 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java
@@ -21,7 +21,6 @@ import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
-import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.CachingPreImageStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedAccount;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
@@ -49,6 +48,8 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
@@ -61,6 +62,9 @@ public abstract class DiffBasedWorldStateUpdateAccumulator slotCache = Caffeine.newBuilder().maximumSize(4000).build();
+
protected final Consumer> accountPreloader;
protected final Consumer storagePreloader;
@@ -260,7 +264,7 @@ public abstract class DiffBasedWorldStateUpdateAccumulator pendingValue =
pendingStorageUpdates.get(slotKey);
@@ -525,8 +528,7 @@ public abstract class DiffBasedWorldStateUpdateAccumulator> localAccountStorage =
storageToUpdate.get(address);
if (localAccountStorage != null) {
@@ -615,11 +615,6 @@ public abstract class DiffBasedWorldStateUpdateAccumulator copy();
protected abstract ACCOUNT copyAccount(final ACCOUNT account);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStatePreimageStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStatePreimageStorage.java
index fde6572aa8..a48aa47c79 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStatePreimageStorage.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStatePreimageStorage.java
@@ -28,6 +28,14 @@ public interface WorldStatePreimageStorage {
Optional getAccountTrieKeyPreimage(Bytes32 trieKey);
+ /**
+ * This method indicates whether this Pre-Image store is "complete", meaning it has all of the
+ * hash preimages for all entries in the state trie.
+ *
+ * @return boolean indicating whether the pre-image store is complete or not
+ */
+ boolean canSupportStreaming();
+
Updater updater();
interface Updater {
diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapServerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapServerTest.java
index 2844603429..f558b44b4e 100644
--- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapServerTest.java
+++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapServerTest.java
@@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.eth.messages.snap.TrieNodesMessage;
import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
+import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.CompactEncoding;
import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
@@ -99,7 +100,8 @@ public class SnapServerTest {
}
},
storage,
- new InMemoryKeyValueStorage());
+ new InMemoryKeyValueStorage(),
+ new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()));
final WorldStateStorageCoordinator storageCoordinator =
new WorldStateStorageCoordinator(inMemoryStorage);
diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java
index 8fb5ce7079..d476ea8fd6 100644
--- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java
+++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java
@@ -248,7 +248,7 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
}
@Override
- public synchronized void saveTrieLog(
+ public synchronized Optional saveTrieLog(
final DiffBasedWorldStateUpdateAccumulator> localUpdater,
final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader,
@@ -257,6 +257,7 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader);
trieLogCache.put(forBlockHeader.getHash(), trieLogFactory.serialize(trieLog));
trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog)));
+ return Optional.of(trieLog);
}
@Override
diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle
index 5733908d57..929e4bda90 100644
--- a/plugin-api/build.gradle
+++ b/plugin-api/build.gradle
@@ -71,7 +71,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
- knownHash = 'TFtDm/CF5Z36eh4XYAwuiPKyo1pm+da/DIzpQYQ//EU='
+ knownHash = 'fM8N/NxUB5CBc/rtAhPDUIGtnkbs1Bb9CFLLeVnqouQ='
}
check.dependsOn('checkAPIChanges')
diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java
index 2cd933e2f8..cc3e616c06 100644
--- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java
+++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/KeyValueStorage.java
@@ -143,4 +143,11 @@ public interface KeyValueStorage extends Closeable {
* @return boolean indicating whether the storage is closed.
*/
boolean isClosed();
+
+ /**
+ * Is this storage persistent or ephemeral.
+ *
+ * @return whether this storage type is persistent or not.
+ */
+ boolean isPersistent();
}
diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java
index 4f734c7c97..340a863de0 100644
--- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java
+++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorage.java
@@ -195,4 +195,11 @@ public interface SegmentedKeyValueStorage extends Closeable {
return value.map(Bytes::wrap);
}
}
+
+ /**
+ * Whether this storage is persistent or ephemeral.
+ *
+ * @return if storage is persistent.
+ */
+ boolean isPersistent();
}
diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java
index 72976a9d84..69ebdcb454 100644
--- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java
+++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueSnapshot.java
@@ -157,6 +157,11 @@ public class RocksDBColumnarKeyValueSnapshot
return closed.get();
}
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
@Override
public void clear(final SegmentIdentifier segment) {
throw new UnsupportedOperationException(
diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java
index 0bf107ddb0..d9648945ec 100644
--- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java
+++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java
@@ -482,4 +482,9 @@ public abstract class RocksDBColumnarKeyValueStorage implements SegmentedKeyValu
return String.format("'%s'(%s)", name, Bytes.of(id).toHexString());
}
}
+
+ @Override
+ public boolean isPersistent() {
+ return true;
+ }
}
diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java
index 930783d7be..bc98322af8 100644
--- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java
+++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/InMemoryKeyValueStorage.java
@@ -101,4 +101,9 @@ public class InMemoryKeyValueStorage extends SegmentedKeyValueStorageAdapter {
public void dump(final PrintStream ps) {
((SegmentedInMemoryKeyValueStorage) storage).dump(ps);
}
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
}
diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java
index aa52e49284..6afae23860 100644
--- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java
+++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/LimitedInMemoryKeyValueStorage.java
@@ -162,6 +162,11 @@ public class LimitedInMemoryKeyValueStorage implements KeyValueStorage {
return false;
}
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
private class MemoryTransaction implements KeyValueStorageTransaction {
private Map updatedValues = new HashMap<>();
diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java
index a7cedca362..12e30d8803 100644
--- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java
+++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java
@@ -310,6 +310,11 @@ public class SegmentedInMemoryKeyValueStorage
return false;
}
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
@Override
public SegmentedInMemoryKeyValueStorage takeSnapshot() {
// need to clone the submaps also:
diff --git a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java
index 28c2d4c796..e85fb542b0 100644
--- a/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java
+++ b/services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedKeyValueStorageAdapter.java
@@ -130,6 +130,11 @@ public class SegmentedKeyValueStorageAdapter implements KeyValueStorage {
return storage.isClosed();
}
+ @Override
+ public boolean isPersistent() {
+ return storage.isPersistent();
+ }
+
private void throwIfClosed() {
if (storage.isClosed()) {
LOG.error("Attempting to use a closed Storage instance.");