Skip to content

Commit cab46aa

Browse files
committed
move hashing and preImage functions into a PreImageProxy class
[skip ci] Signed-off-by: garyschulte <garyschulte@gmail.com>
1 parent 1618f33 commit cab46aa

File tree

10 files changed

+219
-122
lines changed

10 files changed

+219
-122
lines changed

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@
3636
import java.util.Map;
3737
import java.util.NavigableMap;
3838
import java.util.Objects;
39-
import java.util.Optional;
40-
import java.util.TreeMap;
41-
import java.util.stream.Collectors;
4239

4340
import org.apache.tuweni.bytes.Bytes;
4441
import org.apache.tuweni.bytes.Bytes32;
Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,86 @@
1-
package org.hyperledger.besu.ethereum.bonsai.storage;public interface BonsaiPreImageProxy {
1+
/*
2+
* Copyright Hyperledger Besu Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*
15+
*/
16+
package org.hyperledger.besu.ethereum.bonsai.storage;
17+
18+
import org.hyperledger.besu.datatypes.Address;
19+
import org.hyperledger.besu.datatypes.Hash;
20+
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
21+
22+
import java.util.Optional;
23+
24+
import com.google.common.collect.BiMap;
25+
import com.google.common.collect.HashBiMap;
26+
import org.apache.tuweni.bytes.Bytes;
27+
import org.apache.tuweni.bytes.Bytes32;
28+
import org.apache.tuweni.units.bigints.UInt256;
29+
30+
/** Acts as both a Hasher and PreImageStorage for Bonsai storage format. */
31+
public interface BonsaiPreImageProxy extends WorldStatePreimageStorage {
32+
/**
33+
* If this value is not already present, save in preImage store and return the hash value.
34+
*
35+
* @param value value to hash
36+
* @return Hash of value
37+
*/
38+
Hash hashAndSavePreImage(Bytes value);
39+
40+
/** PreImageProxy which does not store or cache preImages and only implements hashing. */
41+
class NoOpPreImageProxy implements BonsaiPreImageProxy {
42+
43+
@Override
44+
public Hash hashAndSavePreImage(final Bytes value) {
45+
return Hash.hash(value);
46+
}
47+
48+
@Override
49+
public Optional<UInt256> getStorageTrieKeyPreimage(final Bytes32 trieKey) {
50+
return Optional.empty();
51+
}
52+
53+
@Override
54+
public Optional<Address> getAccountTrieKeyPreimage(final Bytes32 trieKey) {
55+
return Optional.empty();
56+
}
57+
58+
@Override
59+
public Updater updater() {
60+
throw new UnsupportedOperationException("NoOpPreImageProxy does not implement an updater");
61+
}
62+
}
63+
64+
/**
65+
* A caching PreImageProxy suitable for ReferenceTestWorldState which saves hashes in an unbounded
66+
* BiMap.
67+
*/
68+
class BonsaiReferenceTestPreImageProxy extends NoOpPreImageProxy {
69+
BiMap<Hash, Bytes> preImageCache = HashBiMap.create();
70+
71+
@Override
72+
public Hash hashAndSavePreImage(final Bytes value) {
73+
return preImageCache.inverse().computeIfAbsent(value, Hash::hash);
74+
}
75+
76+
@Override
77+
public Optional<UInt256> getStorageTrieKeyPreimage(final Bytes32 trieKey) {
78+
return Optional.ofNullable(preImageCache.get(trieKey)).map(UInt256::fromBytes);
79+
}
80+
81+
@Override
82+
public Optional<Address> getAccountTrieKeyPreimage(final Bytes32 trieKey) {
83+
return Optional.ofNullable(preImageCache.get(trieKey)).map(Address::wrap);
84+
}
85+
}
286
}

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ public BonsaiSnapshotWorldStateKeyValueStorage(
4444
final BonsaiWorldStateKeyValueStorage parentWorldStateStorage,
4545
final SnappedKeyValueStorage segmentedWorldStateStorage,
4646
final KeyValueStorage trieLogStorage,
47-
final ObservableMetricsSystem metricsSystem) {
47+
final ObservableMetricsSystem metricsSystem,
48+
final BonsaiPreImageProxy preImageProxy) {
4849
super(
4950
parentWorldStateStorage.flatDbMode,
5051
parentWorldStateStorage.flatDbReaderStrategy,
5152
segmentedWorldStateStorage,
5253
trieLogStorage,
53-
metricsSystem);
54+
metricsSystem,
55+
preImageProxy);
5456
this.parentWorldStateStorage = parentWorldStateStorage;
5557
this.subscribeParentId = parentWorldStateStorage.subscribe(this);
5658
}
@@ -62,7 +64,8 @@ public BonsaiSnapshotWorldStateKeyValueStorage(
6264
worldStateStorage,
6365
((SnappableKeyValueStorage) worldStateStorage.composedWorldStateStorage).takeSnapshot(),
6466
worldStateStorage.trieLogStorage,
65-
metricsSystem);
67+
metricsSystem,
68+
worldStateStorage.preImageProxy);
6669
}
6770

6871
private boolean isClosedGet() {

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE;
2020
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
2121

22-
import org.apache.tuweni.units.bigints.UInt256;
22+
import org.hyperledger.besu.datatypes.Address;
2323
import org.hyperledger.besu.datatypes.Hash;
2424
import org.hyperledger.besu.datatypes.StorageSlotKey;
25+
import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount;
2526
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FlatDbReaderStrategy;
2627
import org.hyperledger.besu.ethereum.bonsai.storage.flat.FullFlatDbReaderStrategy;
2728
import org.hyperledger.besu.ethereum.bonsai.storage.flat.PartialFlatDbReaderStrategy;
29+
import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldView;
2830
import org.hyperledger.besu.ethereum.storage.StorageProvider;
2931
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
3032
import org.hyperledger.besu.ethereum.trie.MerkleTrie;
@@ -33,6 +35,7 @@
3335
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
3436
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
3537
import org.hyperledger.besu.evm.account.AccountStorageEntry;
38+
import org.hyperledger.besu.evm.worldstate.WorldState;
3639
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
3740
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
3841
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
@@ -41,25 +44,28 @@
4144
import org.hyperledger.besu.util.Subscribers;
4245

4346
import java.nio.charset.StandardCharsets;
47+
import java.util.Comparator;
4448
import java.util.List;
4549
import java.util.Map;
4650
import java.util.NavigableMap;
4751
import java.util.Optional;
4852
import java.util.TreeMap;
4953
import java.util.concurrent.atomic.AtomicBoolean;
50-
import java.util.function.Function;
5154
import java.util.function.Predicate;
5255
import java.util.function.Supplier;
5356
import java.util.stream.Collectors;
57+
import java.util.stream.Stream;
5458

5559
import org.apache.tuweni.bytes.Bytes;
5660
import org.apache.tuweni.bytes.Bytes32;
61+
import org.apache.tuweni.units.bigints.UInt256;
5762
import org.slf4j.Logger;
5863
import org.slf4j.LoggerFactory;
5964

6065
@SuppressWarnings("unused")
6166
public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoCloseable {
62-
Bytes32 BYTES32_MAX_VALUE = Bytes32.fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
67+
Bytes32 BYTES32_MAX_VALUE =
68+
Bytes32.fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
6369
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class);
6470

6571
// 0x776f726c64526f6f74
@@ -85,18 +91,25 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC
8591

8692
protected final Subscribers<BonsaiStorageSubscriber> subscribers = Subscribers.create();
8793

88-
// no-op default hash preImage mapper:
89-
protected Function<Hash, Optional<Bytes>> hashPreImageMapper = __ -> Optional.empty();
94+
final BonsaiPreImageProxy preImageProxy;
9095

9196
public BonsaiWorldStateKeyValueStorage(
9297
final StorageProvider provider, final ObservableMetricsSystem metricsSystem) {
98+
this(provider, metricsSystem, new BonsaiPreImageProxy.NoOpPreImageProxy());
99+
}
100+
101+
public BonsaiWorldStateKeyValueStorage(
102+
final StorageProvider provider,
103+
final ObservableMetricsSystem metricsSystem,
104+
final BonsaiPreImageProxy preImageProxy) {
93105
this.composedWorldStateStorage =
94106
provider.getStorageBySegmentIdentifiers(
95107
List.of(
96108
ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE));
97109
this.trieLogStorage =
98110
provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE);
99111
this.metricsSystem = metricsSystem;
112+
this.preImageProxy = preImageProxy;
100113
loadFlatDbStrategy();
101114
}
102115

@@ -105,12 +118,14 @@ public BonsaiWorldStateKeyValueStorage(
105118
final FlatDbReaderStrategy flatDbReaderStrategy,
106119
final SegmentedKeyValueStorage composedWorldStateStorage,
107120
final KeyValueStorage trieLogStorage,
108-
final ObservableMetricsSystem metricsSystem) {
121+
final ObservableMetricsSystem metricsSystem,
122+
final BonsaiPreImageProxy preImageProxy) {
109123
this.flatDbMode = flatDbMode;
110124
this.flatDbReaderStrategy = flatDbReaderStrategy;
111125
this.composedWorldStateStorage = composedWorldStateStorage;
112126
this.trieLogStorage = trieLogStorage;
113127
this.metricsSystem = metricsSystem;
128+
this.preImageProxy = preImageProxy;
114129
}
115130

116131
public void loadFlatDbStrategy() {
@@ -267,31 +282,42 @@ public Map<Bytes32, Bytes> streamFlatStorages(
267282
composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max);
268283
}
269284

270-
/**
271-
* Provide a function to map hash values to an Optional wrapping their corresponding preImage
272-
* or empty if the preImage is not available.
273-
*
274-
* @param hashPreImageMapper preImage mapper function
275-
*/
276-
public void setPreImageMapper(final Function<Hash, Optional<Bytes>> hashPreImageMapper) {
277-
this.hashPreImageMapper = hashPreImageMapper;
278-
}
279-
280-
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(final Hash addressHash,
281-
final Bytes32 startKeyHash, final int limit) {
282-
return streamFlatStorages(addressHash, startKeyHash, BYTES32_MAX_VALUE, limit)
283-
.entrySet()
284-
.stream()
285-
.collect(Collectors.toMap(
285+
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
286+
final Hash addressHash, final Bytes32 startKeyHash, final int limit) {
287+
return streamFlatStorages(addressHash, startKeyHash, BYTES32_MAX_VALUE, limit)
288+
.entrySet()
289+
// map back to slot keys using preImage provider:
290+
.stream()
291+
.collect(
292+
Collectors.toMap(
286293
e -> e.getKey(),
287-
e -> AccountStorageEntry.create(
288-
UInt256.fromBytes(e.getValue()),
289-
Hash.wrap(e.getKey()),
290-
hashPreImageMapper.apply(Hash.wrap(e.getKey()))
291-
.map(UInt256::fromBytes)),
292-
(a,b) -> a,
293-
TreeMap::new
294-
));
294+
e ->
295+
AccountStorageEntry.create(
296+
UInt256.fromBytes(e.getValue()),
297+
Hash.wrap(e.getKey()),
298+
preImageProxy.getStorageTrieKeyPreimage(e.getKey())),
299+
(a, b) -> a,
300+
TreeMap::new));
301+
}
302+
303+
public Stream<WorldState.StreamableAccount> streamAccounts(
304+
final BonsaiWorldView context, final Bytes32 startKeyHash, final int limit) {
305+
return streamFlatAccounts(startKeyHash, BYTES32_MAX_VALUE, Long.MAX_VALUE)
306+
.entrySet()
307+
// map back to addresses using preImage provider:
308+
.stream()
309+
.map(
310+
entry ->
311+
preImageProxy
312+
.getAccountTrieKeyPreimage(entry.getKey())
313+
.map(
314+
address ->
315+
new WorldState.StreamableAccount(
316+
Optional.of(address),
317+
BonsaiAccount.fromRLP(context, address, entry.getValue(), false))))
318+
.filter(Optional::isPresent)
319+
.map(Optional::get)
320+
.sorted(Comparator.comparing(account -> account.getAddress().orElse(Address.ZERO)));
295321
}
296322

297323
@Override

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateLayerStorage.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@ public BonsaiWorldStateLayerStorage(final BonsaiWorldStateKeyValueStorage parent
3030
new LayeredKeyValueStorage(parent.composedWorldStateStorage),
3131
parent.trieLogStorage,
3232
parent,
33-
parent.metricsSystem);
33+
parent.metricsSystem,
34+
parent.preImageProxy);
3435
}
3536

3637
public BonsaiWorldStateLayerStorage(
3738
final SnappedKeyValueStorage composedWorldStateStorage,
3839
final KeyValueStorage trieLogStorage,
3940
final BonsaiWorldStateKeyValueStorage parent,
40-
final ObservableMetricsSystem metricsSystem) {
41-
super(parent, composedWorldStateStorage, trieLogStorage, metricsSystem);
42-
setPreImageMapper(parent.hashPreImageMapper);
41+
final ObservableMetricsSystem metricsSystem,
42+
final BonsaiPreImageProxy preImageProxy) {
43+
super(parent, composedWorldStateStorage, trieLogStorage, metricsSystem, preImageProxy);
4344
}
4445

4546
@Override
@@ -53,6 +54,7 @@ public BonsaiWorldStateLayerStorage clone() {
5354
((LayeredKeyValueStorage) composedWorldStateStorage).clone(),
5455
trieLogStorage,
5556
parentWorldStateStorage,
56-
metricsSystem);
57+
metricsSystem,
58+
preImageProxy);
5759
}
5860
}

0 commit comments

Comments
 (0)