Skip to content

Commit dce531e

Browse files
committed
Implement snap-serving from a Bonsai Archive node and add tests
Signed-off-by: Matthew Whitehead <[email protected]>
1 parent 9858ba4 commit dce531e

File tree

4 files changed

+419
-7
lines changed

4 files changed

+419
-7
lines changed

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/flat/ArchiveFlatDbStrategy.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@
3131
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
3232

3333
import java.util.Optional;
34+
import java.util.function.Function;
3435
import java.util.function.Supplier;
36+
import java.util.stream.Stream;
3537

38+
import kotlin.Pair;
3639
import org.apache.tuweni.bytes.Bytes;
40+
import org.apache.tuweni.bytes.Bytes32;
3741
import org.bouncycastle.util.Arrays;
3842
import org.slf4j.Logger;
3943
import org.slf4j.LoggerFactory;
@@ -103,6 +107,102 @@ public Optional<Bytes> getFlatAccount(
103107
return accountFound;
104108
}
105109

110+
@Override
111+
protected Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
112+
final SegmentedKeyValueStorage storage, final Bytes startKeyHash, final Bytes32 endKeyHash) {
113+
final Stream<Pair<Bytes32, Bytes>> stream =
114+
storage
115+
.streamFromKey(
116+
ACCOUNT_INFO_STATE,
117+
calculateArchiveKeyNoContextMinSuffix(startKeyHash.toArrayUnsafe()),
118+
calculateArchiveKeyNoContextMaxSuffix(endKeyHash.toArrayUnsafe()))
119+
.map(e -> Bytes.of(calculateArchiveKeyNoContextMaxSuffix(trimSuffix(e.getKey()))))
120+
.distinct()
121+
.map(
122+
e ->
123+
new Pair<>(
124+
Bytes32.wrap(trimSuffix(e.toArrayUnsafe())),
125+
Bytes.of(
126+
storage.getNearestBefore(ACCOUNT_INFO_STATE, e).get().value().get())));
127+
return stream;
128+
}
129+
130+
@Override
131+
protected Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
132+
final SegmentedKeyValueStorage storage, final Bytes startKeyHash) {
133+
final Stream<Pair<Bytes32, Bytes>> stream =
134+
storage
135+
.streamFromKey(
136+
ACCOUNT_INFO_STATE,
137+
calculateArchiveKeyNoContextMinSuffix(startKeyHash.toArrayUnsafe()))
138+
.map(e -> Bytes.of(calculateArchiveKeyNoContextMaxSuffix(trimSuffix(e.getKey()))))
139+
.distinct()
140+
.map(
141+
e ->
142+
new Pair<Bytes32, Bytes>(
143+
Bytes32.wrap(trimSuffix(e.toArrayUnsafe())),
144+
Bytes.of(
145+
storage.getNearestBefore(ACCOUNT_INFO_STATE, e).get().value().get())));
146+
return stream;
147+
}
148+
149+
@Override
150+
protected Stream<Pair<Bytes32, Bytes>> storageToPairStream(
151+
final SegmentedKeyValueStorage storage,
152+
final Hash accountHash,
153+
final Bytes startKeyHash,
154+
final Function<Bytes, Bytes> valueMapper) {
155+
return storage
156+
.streamFromKey(
157+
ACCOUNT_STORAGE_STORAGE,
158+
calculateArchiveKeyNoContextMinSuffix(
159+
calculateNaturalSlotKey(accountHash, Hash.wrap(Bytes32.wrap(startKeyHash)))))
160+
.map(e -> Bytes.of(calculateArchiveKeyNoContextMaxSuffix(trimSuffix(e.getKey()))))
161+
.distinct()
162+
.map(
163+
key ->
164+
new Pair<>(
165+
Bytes32.wrap(trimSuffix(key.slice(Hash.SIZE).toArrayUnsafe())),
166+
valueMapper.apply(
167+
Bytes.of(
168+
storage
169+
.getNearestBefore(ACCOUNT_STORAGE_STORAGE, key)
170+
.get()
171+
.value()
172+
.get())
173+
.trimLeadingZeros())));
174+
}
175+
176+
@Override
177+
protected Stream<Pair<Bytes32, Bytes>> storageToPairStream(
178+
final SegmentedKeyValueStorage storage,
179+
final Hash accountHash,
180+
final Bytes startKeyHash,
181+
final Bytes32 endKeyHash,
182+
final Function<Bytes, Bytes> valueMapper) {
183+
return storage
184+
.streamFromKey(
185+
ACCOUNT_STORAGE_STORAGE,
186+
calculateArchiveKeyNoContextMinSuffix(
187+
calculateNaturalSlotKey(accountHash, Hash.wrap(Bytes32.wrap(startKeyHash)))),
188+
calculateArchiveKeyNoContextMaxSuffix(
189+
calculateNaturalSlotKey(accountHash, Hash.wrap(endKeyHash))))
190+
.map(e -> Bytes.of(calculateArchiveKeyNoContextMaxSuffix(trimSuffix(e.getKey()))))
191+
.distinct()
192+
.map(
193+
key ->
194+
new Pair<>(
195+
Bytes32.wrap(trimSuffix(key.slice(Hash.SIZE).toArrayUnsafe())),
196+
valueMapper.apply(
197+
Bytes.of(
198+
storage
199+
.getNearestBefore(ACCOUNT_STORAGE_STORAGE, key)
200+
.get()
201+
.value()
202+
.get())
203+
.trimLeadingZeros())));
204+
}
205+
106206
/*
107207
* Puts the account data for the given account hash and block context.
108208
*/
@@ -128,6 +228,10 @@ public void removeFlatAccount(
128228
transaction.put(ACCOUNT_INFO_STATE, keySuffixed, DELETED_ACCOUNT_VALUE);
129229
}
130230

231+
private byte[] trimSuffix(final byte[] suffixedAddress) {
232+
return Arrays.copyOfRange(suffixedAddress, 0, suffixedAddress.length - 8);
233+
}
234+
131235
/*
132236
* Retrieves the storage value for the given account hash and storage slot key, using the world state root hash supplier, storage root supplier, and node loader.
133237
*/
@@ -232,6 +336,14 @@ public static byte[] calculateArchiveKeyWithMinSuffix(
232336
return calculateArchiveKeyWithSuffix(context, naturalKey, MIN_BLOCK_SUFFIX);
233337
}
234338

339+
public static byte[] calculateArchiveKeyNoContextMinSuffix(final byte[] naturalKey) {
340+
return Arrays.concatenate(naturalKey, MIN_BLOCK_SUFFIX);
341+
}
342+
343+
public static byte[] calculateArchiveKeyNoContextMaxSuffix(final byte[] naturalKey) {
344+
return Arrays.concatenate(naturalKey, MAX_BLOCK_SUFFIX);
345+
}
346+
235347
public static Bytes calculateArchiveKeyWithMaxSuffix(
236348
final BonsaiContext context, final byte[] naturalKey) {
237349
return Bytes.of(calculateArchiveKeyWithSuffix(context, naturalKey, MAX_BLOCK_SUFFIX));

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/FlatDbStrategy.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public NavigableMap<Bytes32, Bytes> streamStorageFlatDatabase(
250250
.takeWhile(takeWhile));
251251
}
252252

253-
private static Stream<Pair<Bytes32, Bytes>> storageToPairStream(
253+
protected Stream<Pair<Bytes32, Bytes>> storageToPairStream(
254254
final SegmentedKeyValueStorage storage,
255255
final Hash accountHash,
256256
final Bytes startKeyHash,
@@ -267,7 +267,7 @@ private static Stream<Pair<Bytes32, Bytes>> storageToPairStream(
267267
valueMapper.apply(Bytes.wrap(pair.getValue()).trimLeadingZeros())));
268268
}
269269

270-
private static Stream<Pair<Bytes32, Bytes>> storageToPairStream(
270+
protected Stream<Pair<Bytes32, Bytes>> storageToPairStream(
271271
final SegmentedKeyValueStorage storage,
272272
final Hash accountHash,
273273
final Bytes startKeyHash,
@@ -286,14 +286,14 @@ private static Stream<Pair<Bytes32, Bytes>> storageToPairStream(
286286
valueMapper.apply(Bytes.wrap(pair.getValue()).trimLeadingZeros())));
287287
}
288288

289-
private static Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
289+
protected Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
290290
final SegmentedKeyValueStorage storage, final Bytes startKeyHash, final Bytes32 endKeyHash) {
291291
return storage
292292
.streamFromKey(ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe(), endKeyHash.toArrayUnsafe())
293293
.map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue())));
294294
}
295295

296-
private static Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
296+
protected Stream<Pair<Bytes32, Bytes>> accountsToPairStream(
297297
final SegmentedKeyValueStorage storage, final Bytes startKeyHash) {
298298
return storage
299299
.streamFromKey(ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe())

0 commit comments

Comments
 (0)