Skip to content

Commit 2602260

Browse files
Merge branch 'main' into feat/bal_devnet_test_v5.6.1
2 parents cb7a375 + b1af1fe commit 2602260

File tree

19 files changed

+947
-49
lines changed

19 files changed

+947
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ are provided with different values, using input as per the execution-apis spec i
5151
- Support [EIP-8189](https://eips.ethereum.org/EIPS/eip-8189): snap/2 - block access list exchange
5252
- Limit pooled tx requests by size and remove pre-eth/68 transaction announcement support [#9990](https://github.com/besu-eth/besu/pull/9990)
5353
- Reduce tx p2p broadcast bandwidth and memory used [#9937](https://github.com/besu-eth/besu/pull/9937)
54+
- Improve syncing time of the experimental Bonsai Archive storage by migrating after a Bonsai full sync [#9979](https://github.com/besu-eth/besu/pull/9997)
5455

5556
### Plugin API
5657
- Plugin API: Allow the registration of multiple PluginTransactionPoolValidatorFactory [#9964](https://github.com/hyperledger/besu/pull/9964)

app/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,15 @@
9292
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
9393
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.cache.CodeCache;
9494
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
95+
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.storage.flat.BonsaiArchiveFlatDbStrategy;
9596
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.worldview.BonsaiArchiver;
97+
import org.hyperledger.besu.ethereum.trie.pathbased.bonsaiarchive.BonsaiFlatDbToArchiveMigrator;
9698
import org.hyperledger.besu.ethereum.trie.pathbased.common.storage.PathBasedWorldStateKeyValueStorage;
99+
import org.hyperledger.besu.ethereum.trie.pathbased.common.storage.flat.CodeHashCodeStorageStrategy;
97100
import org.hyperledger.besu.ethereum.trie.pathbased.common.trielog.TrieLogManager;
98101
import org.hyperledger.besu.ethereum.trie.pathbased.common.trielog.TrieLogPruner;
99102
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
103+
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
100104
import org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration;
101105
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
102106
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive.WorldStateHealer;
@@ -121,6 +125,8 @@
121125
import java.util.Map;
122126
import java.util.Optional;
123127
import java.util.OptionalLong;
128+
import java.util.concurrent.ScheduledExecutorService;
129+
import java.util.concurrent.atomic.AtomicBoolean;
124130
import java.util.concurrent.atomic.AtomicLong;
125131
import java.util.concurrent.atomic.AtomicReference;
126132
import java.util.function.Supplier;
@@ -888,6 +894,10 @@ public BesuController build() {
888894
}
889895
}
890896

897+
final List<Closeable> closeables = new ArrayList<>();
898+
closeables.add(protocolContext.getWorldStateArchive());
899+
closeables.add(storageProvider);
900+
891901
if (DataStorageFormat.X_BONSAI_ARCHIVE.equals(
892902
dataStorageConfiguration.getDataStorageFormat())) {
893903
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
@@ -898,12 +908,38 @@ public BesuController build() {
898908
blockchain,
899909
scheduler,
900910
((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager());
901-
blockchain.observeBlockAdded(archiver);
902-
}
903911

904-
final List<Closeable> closeables = new ArrayList<>();
905-
closeables.add(protocolContext.getWorldStateArchive());
906-
closeables.add(storageProvider);
912+
if (worldStateStorageCoordinator.isMatchingFlatMode(FlatDbMode.FULL)
913+
|| worldStateStorageCoordinator.isMatchingFlatMode(FlatDbMode.PARTIAL)) {
914+
final BonsaiFlatDbToArchiveMigrator archiveMigrator =
915+
createArchiveMigrator(worldStateStorageCoordinator, worldStateArchive, blockchain);
916+
closeables.add(archiveMigrator);
917+
918+
final AtomicBoolean migrationStarted = new AtomicBoolean(false);
919+
final AtomicLong syncSubscriptionId = new AtomicLong();
920+
syncSubscriptionId.set(
921+
synchronizer.subscribeInSync(
922+
(inSync) -> {
923+
if (inSync && migrationStarted.compareAndSet(false, true)) {
924+
synchronizer.unsubscribeInSync(syncSubscriptionId.get());
925+
LOG.info("Node is in sync, starting Bonsai archive migration");
926+
archiveMigrator
927+
.migrate()
928+
.thenRun(() -> blockchain.observeBlockAdded(archiver))
929+
.exceptionally(
930+
error -> {
931+
LOG.error(
932+
"Archive migration failed, archiver will remain disabled until restart",
933+
error);
934+
return null;
935+
});
936+
}
937+
},
938+
0));
939+
} else {
940+
blockchain.observeBlockAdded(archiver);
941+
}
942+
}
907943

908944
return new BesuController(
909945
protocolSchedule,
@@ -1011,6 +1047,27 @@ private BonsaiArchiver createBonsaiArchiver(
10111047
return archiver;
10121048
}
10131049

1050+
private BonsaiFlatDbToArchiveMigrator createArchiveMigrator(
1051+
final WorldStateStorageCoordinator worldStateStorageCoordinator,
1052+
final WorldStateArchive worldStateArchive,
1053+
final Blockchain blockchain) {
1054+
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
1055+
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
1056+
final TrieLogManager trieLogManager =
1057+
((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager();
1058+
final ScheduledExecutorService migrationExecutor =
1059+
MonitoredExecutors.newScheduledThreadPool("archive-migrator", 1, metricsSystem);
1060+
final BonsaiArchiveFlatDbStrategy archiveStrategy =
1061+
new BonsaiArchiveFlatDbStrategy(metricsSystem, new CodeHashCodeStorageStrategy());
1062+
return new BonsaiFlatDbToArchiveMigrator(
1063+
worldStateKeyValueStorage,
1064+
trieLogManager,
1065+
blockchain,
1066+
migrationExecutor,
1067+
metricsSystem,
1068+
archiveStrategy);
1069+
}
1070+
10141071
/**
10151072
* Create synchronizer synchronizer.
10161073
*

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/BonsaiArchiveWorldStateProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
2525
import org.hyperledger.besu.ethereum.trie.pathbased.common.provider.WorldStateQueryParams;
2626
import org.hyperledger.besu.ethereum.trie.pathbased.common.worldview.PathBasedWorldState;
27+
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
2728
import org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration;
2829
import org.hyperledger.besu.evm.internal.EvmConfiguration;
2930
import org.hyperledger.besu.plugin.ServiceManager;
@@ -60,6 +61,12 @@ public BonsaiArchiveWorldStateProvider(
6061

6162
@Override
6263
public Optional<MutableWorldState> getWorldState(final WorldStateQueryParams queryParams) {
64+
// If not in archive mode then the migration is not yet complete, so fallback to
65+
// the regular BonsaiWorldStateProvider
66+
if (!worldStateKeyValueStorage.getFlatDbMode().equals(FlatDbMode.ARCHIVE)) {
67+
return super.getWorldState(queryParams);
68+
}
69+
6370
if (queryParams.shouldWorldStateUpdateHead()) {
6471
return getFullWorldState(queryParams);
6572
} else {

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,13 @@
4747

4848
import org.apache.tuweni.bytes.Bytes;
4949
import org.apache.tuweni.bytes.Bytes32;
50+
import org.slf4j.Logger;
51+
import org.slf4j.LoggerFactory;
5052

5153
public class BonsaiWorldStateKeyValueStorage extends PathBasedWorldStateKeyValueStorage
5254
implements WorldStateKeyValueStorage {
55+
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class);
56+
5357
protected final BonsaiFlatDbStrategyProvider flatDbStrategyProvider;
5458

5559
public BonsaiWorldStateKeyValueStorage(
@@ -167,6 +171,21 @@ public void upgradeToFullFlatDbMode() {
167171
flatDbStrategyProvider.upgradeToFullFlatDbMode(composedWorldStateStorage);
168172
}
169173

174+
public void upgradeToArchiveFlatDbMode() {
175+
flatDbStrategyProvider.upgradeToArchiveFlatDbMode(composedWorldStateStorage);
176+
// Invalidate cached world state snapshots that were created under the previous strategy.
177+
// Snapshots share the flatDbStrategyProvider, so after the switch they would use the new
178+
// ARCHIVE read path against stale snapshot data that lacks complete archive-keyed entries.
179+
subscribers.forEach(
180+
subscriber -> {
181+
try {
182+
subscriber.onClearFlatDatabaseStorage();
183+
} catch (final Exception e) {
184+
LOG.error("Error notifying subscriber of flat database storage upgrade", e);
185+
}
186+
});
187+
}
188+
170189
public void downgradeToPartialFlatDbMode() {
171190
flatDbStrategyProvider.downgradeToPartialFlatDbMode(composedWorldStateStorage);
172191
}

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/storage/flat/BonsaiArchiveFlatDbStrategy.java

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -281,20 +281,33 @@ protected Stream<Pair<Bytes32, Bytes>> storageToPairStream(
281281
}
282282

283283
/*
284-
* Puts the account data for the given account hash and block context.
284+
* Puts the account data for the given account hash.
285285
*/
286286
@Override
287287
public void putFlatAccount(
288288
final SegmentedKeyValueStorage storage,
289289
final SegmentedKeyValueStorageTransaction transaction,
290290
final Hash accountHash,
291291
final Bytes accountValue) {
292+
putFlatAccount(
293+
getStateArchiveContextForWrite(storage).get(), transaction, accountHash, accountValue);
294+
}
292295

293-
// key suffixed with block context, or MIN_BLOCK_SUFFIX if we have no context:
296+
/**
297+
* Puts the account data for the given account hash and block context.
298+
*
299+
* @param context the block context supplying the block number suffix for the archive key
300+
* @param transaction the transaction to write into
301+
* @param accountHash the hash of the account address
302+
* @param accountValue the RLP-encoded account value
303+
*/
304+
public void putFlatAccount(
305+
final BonsaiContext context,
306+
final SegmentedKeyValueStorageTransaction transaction,
307+
final Hash accountHash,
308+
final Bytes accountValue) {
294309
byte[] keySuffixed =
295-
calculateArchiveKeyWithMinSuffix(
296-
getStateArchiveContextForWrite(storage).get(), accountHash.getBytes().toArrayUnsafe());
297-
310+
calculateArchiveKeyWithMinSuffix(context, accountHash.getBytes().toArrayUnsafe());
298311
transaction.put(ACCOUNT_INFO_STATE_ARCHIVE, keySuffixed, accountValue.toArrayUnsafe());
299312
}
300313

@@ -303,12 +316,22 @@ public void removeFlatAccount(
303316
final SegmentedKeyValueStorage storage,
304317
final SegmentedKeyValueStorageTransaction transaction,
305318
final Hash accountHash) {
319+
removeFlatAccount(getStateArchiveContextForWrite(storage).get(), transaction, accountHash);
320+
}
306321

307-
// insert a key suffixed with block context, with 'deleted account' value
322+
/**
323+
* Removes account data for the given account hash and block context.
324+
*
325+
* @param context the block context supplying the block number suffix for the archive key
326+
* @param transaction the transaction to write into
327+
* @param accountHash the hash of the account address
328+
*/
329+
public void removeFlatAccount(
330+
final BonsaiContext context,
331+
final SegmentedKeyValueStorageTransaction transaction,
332+
final Hash accountHash) {
308333
byte[] keySuffixed =
309-
calculateArchiveKeyWithMinSuffix(
310-
getStateArchiveContextForWrite(storage).get(), accountHash.getBytes().toArrayUnsafe());
311-
334+
calculateArchiveKeyWithMinSuffix(context, accountHash.getBytes().toArrayUnsafe());
312335
transaction.put(ACCOUNT_INFO_STATE_ARCHIVE, keySuffixed, DELETED_ACCOUNT_VALUE);
313336
}
314337

@@ -390,13 +413,33 @@ public void putFlatAccountStorageValueByStorageSlotHash(
390413
final Hash accountHash,
391414
final Hash slotHash,
392415
final Bytes storageValue) {
416+
putFlatAccountStorageValueByStorageSlotHash(
417+
getStateArchiveContextForWrite(storage).get(),
418+
transaction,
419+
accountHash,
420+
slotHash,
421+
storageValue);
422+
}
393423

424+
/**
425+
* Puts the storage value for the given account hash and storage slot key for a given context.
426+
*
427+
* @param context the block context supplying the block number suffix for the archive key
428+
* @param transaction the transaction to write into
429+
* @param accountHash the hash of the account address
430+
* @param slotHash the hash of the storage slot key
431+
* @param storageValue the storage value
432+
*/
433+
public void putFlatAccountStorageValueByStorageSlotHash(
434+
final BonsaiContext context,
435+
final SegmentedKeyValueStorageTransaction transaction,
436+
final Hash accountHash,
437+
final Hash slotHash,
438+
final Bytes storageValue) {
394439
// get natural key from account hash and slot key
395440
byte[] naturalKey = calculateNaturalSlotKey(accountHash, slotHash);
396441
// keyNearest, use MIN_BLOCK_SUFFIX in the absence of a block context:
397-
byte[] keyNearest =
398-
calculateArchiveKeyWithMinSuffix(getStateArchiveContextForWrite(storage).get(), naturalKey);
399-
442+
byte[] keyNearest = calculateArchiveKeyWithMinSuffix(context, naturalKey);
400443
transaction.put(ACCOUNT_STORAGE_ARCHIVE, keyNearest, storageValue.toArrayUnsafe());
401444
}
402445

@@ -409,13 +452,27 @@ public void removeFlatAccountStorageValueByStorageSlotHash(
409452
final SegmentedKeyValueStorageTransaction transaction,
410453
final Hash accountHash,
411454
final Hash slotHash) {
455+
removeFlatAccountStorageValueByStorageSlotHash(
456+
getStateArchiveContextForWrite(storage).get(), transaction, accountHash, slotHash);
457+
}
412458

459+
/**
460+
* Removes the storage value for the given account hash and storage slot key for a given context.
461+
*
462+
* @param context the block context supplying the block number suffix for the archive key
463+
* @param transaction the transaction to write into
464+
* @param accountHash the hash of the account address
465+
* @param slotHash the hash of the storage slot key
466+
*/
467+
public void removeFlatAccountStorageValueByStorageSlotHash(
468+
final BonsaiContext context,
469+
final SegmentedKeyValueStorageTransaction transaction,
470+
final Hash accountHash,
471+
final Hash slotHash) {
413472
// get natural key from account hash and slot key
414473
byte[] naturalKey = calculateNaturalSlotKey(accountHash, slotHash);
415474
// insert a key suffixed with block context, with 'deleted account' value
416-
byte[] keySuffixed =
417-
calculateArchiveKeyWithMinSuffix(getStateArchiveContextForWrite(storage).get(), naturalKey);
418-
475+
byte[] keySuffixed = calculateArchiveKeyWithMinSuffix(context, naturalKey);
419476
transaction.put(ACCOUNT_STORAGE_ARCHIVE, keySuffixed, DELETED_STORAGE_VALUE);
420477
}
421478

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/storage/flat/BonsaiFlatDbStrategyProvider.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
2323
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
2424
import org.hyperledger.besu.plugin.services.MetricsSystem;
25-
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
2625
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage;
2726
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
2827

@@ -45,11 +44,7 @@ protected FlatDbMode getRequestedFlatDbMode(
4544
.getPathBasedExtraStorageConfiguration()
4645
.getUnstable()
4746
.getFullFlatDbEnabled()
48-
? (dataStorageConfiguration
49-
.getDataStorageFormat()
50-
.equals(DataStorageFormat.X_BONSAI_ARCHIVE)
51-
? FlatDbMode.ARCHIVE
52-
: FlatDbMode.FULL)
47+
? FlatDbMode.FULL
5348
: FlatDbMode.PARTIAL;
5449
}
5550

@@ -61,16 +56,19 @@ protected FlatDbMode alternativeFlatDbModeForExistingDatabase() {
6156
public void upgradeToFullFlatDbMode(final SegmentedKeyValueStorage composedWorldStateStorage) {
6257
final SegmentedKeyValueStorageTransaction transaction =
6358
composedWorldStateStorage.startTransaction();
64-
if (dataStorageConfiguration.getDataStorageFormat() == DataStorageFormat.BONSAI) {
65-
LOG.info("setting FlatDbStrategy to FULL");
66-
transaction.put(
67-
TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.FULL.getVersion().toArrayUnsafe());
68-
} else if (dataStorageConfiguration.getDataStorageFormat()
69-
== DataStorageFormat.X_BONSAI_ARCHIVE) {
70-
LOG.info("setting FlatDbStrategy to ARCHIVE");
71-
transaction.put(
72-
TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.ARCHIVE.getVersion().toArrayUnsafe());
73-
}
59+
LOG.info("setting FlatDbStrategy to FULL");
60+
transaction.put(
61+
TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.FULL.getVersion().toArrayUnsafe());
62+
transaction.commit();
63+
loadFlatDbStrategy(composedWorldStateStorage); // force reload of flat db reader strategy
64+
}
65+
66+
public void upgradeToArchiveFlatDbMode(final SegmentedKeyValueStorage composedWorldStateStorage) {
67+
final SegmentedKeyValueStorageTransaction transaction =
68+
composedWorldStateStorage.startTransaction();
69+
LOG.info("setting FlatDbStrategy to ARCHIVE");
70+
transaction.put(
71+
TRIE_BRANCH_STORAGE, FLAT_DB_MODE, FlatDbMode.ARCHIVE.getVersion().toArrayUnsafe());
7472
transaction.commit();
7573
loadFlatDbStrategy(composedWorldStateStorage); // force reload of flat db reader strategy
7674
}

0 commit comments

Comments
 (0)