Skip to content

Commit 1160bb3

Browse files
authored
Deposit tree snapshots should only be queried/loaded once (Consensys#8113)
1 parent 02110f1 commit 1160bb3

File tree

6 files changed

+115
-55
lines changed

6 files changed

+115
-55
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ the [releases page](https://github.com/Consensys/teku/releases).
2020
- Increased the attestation cache capacity to allow Teku a bigger pool of attestations when block building.
2121
- Defaulted `--builder-bid-compare-factor` to 90. This makes it necessary for external block builders to give at least 10% additional profit compared to a local build before being taken into consideration. If you would like to go back to the previous default, set `--builder-bid-compare-factor` to 100.
2222
- Added `--p2p-direct-peers` command line option to configure explicit peers as per [Explicit Peering Agreements](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#explicit-peering-agreements) libp2p spec.
23+
- Deposit tree snapshots will be loaded from database as a default unless custom snapshot has been provided.
2324

2425
### Bug Fixes
2526
- Fix incompatibility between Teku validator client and Lighthouse beacon nodes [#8117](https://github.com/Consensys/teku/pull/8117)

Diff for: beacon/pow/src/main/java/tech/pegasys/teku/beacon/pow/DepositSnapshotStorageLoader.java

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
package tech.pegasys.teku.beacon.pow;
1515

16+
import static tech.pegasys.teku.infrastructure.logging.StatusLogger.STATUS_LOG;
17+
1618
import tech.pegasys.teku.ethereum.pow.api.schema.LoadDepositSnapshotResult;
1719
import tech.pegasys.teku.infrastructure.async.SafeFuture;
1820
import tech.pegasys.teku.storage.api.StorageQueryChannel;
@@ -31,6 +33,8 @@ public SafeFuture<LoadDepositSnapshotResult> loadDepositSnapshot() {
3133
if (!depositSnapshotStorageEnabled) {
3234
return SafeFuture.completedFuture(LoadDepositSnapshotResult.EMPTY);
3335
}
36+
37+
STATUS_LOG.loadingDepositSnapshotFromDb();
3438
return historicalChainData
3539
.getFinalizedDepositSnapshot()
3640
.thenApply(LoadDepositSnapshotResult::create);

Diff for: beacon/pow/src/main/java/tech/pegasys/teku/beacon/pow/Eth1DepositManager.java

+24-27
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.google.common.base.Preconditions;
2222
import java.math.BigInteger;
2323
import java.util.Optional;
24-
import org.apache.commons.lang3.ObjectUtils;
2524
import org.apache.logging.log4j.LogManager;
2625
import org.apache.logging.log4j.Logger;
2726
import org.web3j.protocol.core.methods.response.EthBlock;
@@ -47,7 +46,7 @@ public class Eth1DepositManager {
4746
private final Eth1DepositStorageChannel eth1DepositStorageChannel;
4847
private final DepositSnapshotFileLoader depositSnapshotFileLoader;
4948
private final DepositSnapshotStorageLoader depositSnapshotStorageLoader;
50-
private final boolean takeBestDepositSnapshot;
49+
private final boolean customDepositSnapshotPathPresent;
5150
private final DepositProcessingController depositProcessingController;
5251
private final MinimumGenesisTimeBlockFinder minimumGenesisTimeBlockFinder;
5352
private final Optional<UInt64> depositContractDeployBlock;
@@ -61,7 +60,7 @@ public Eth1DepositManager(
6160
final Eth1DepositStorageChannel eth1DepositStorageChannel,
6261
final DepositSnapshotFileLoader depositSnapshotFileLoader,
6362
final DepositSnapshotStorageLoader depositSnapshotStorageLoader,
64-
final boolean takeBestDepositSnapshot,
63+
final boolean customDepositSnapshotPathPresent,
6564
final DepositProcessingController depositProcessingController,
6665
final MinimumGenesisTimeBlockFinder minimumGenesisTimeBlockFinder,
6766
final Optional<UInt64> depositContractDeployBlock,
@@ -73,7 +72,7 @@ public Eth1DepositManager(
7372
this.eth1DepositStorageChannel = eth1DepositStorageChannel;
7473
this.depositSnapshotFileLoader = depositSnapshotFileLoader;
7574
this.depositSnapshotStorageLoader = depositSnapshotStorageLoader;
76-
this.takeBestDepositSnapshot = takeBestDepositSnapshot;
75+
this.customDepositSnapshotPathPresent = customDepositSnapshotPathPresent;
7776
this.depositProcessingController = depositProcessingController;
7877
this.minimumGenesisTimeBlockFinder = minimumGenesisTimeBlockFinder;
7978
this.depositContractDeployBlock = depositContractDeployBlock;
@@ -118,31 +117,29 @@ public void start() {
118117
}
119118

120119
private SafeFuture<LoadDepositSnapshotResult> loadDepositSnapshot() {
121-
final LoadDepositSnapshotResult fileDepositSnapshotResult =
122-
depositSnapshotFileLoader.loadDepositSnapshot();
123-
if (fileDepositSnapshotResult.getDepositTreeSnapshot().isPresent()
124-
&& !takeBestDepositSnapshot) {
125-
LOG.debug("Deposit snapshot from file is provided, using it");
126-
return SafeFuture.completedFuture(fileDepositSnapshotResult);
120+
if (customDepositSnapshotPathPresent) {
121+
LOG.debug("Custom deposit snapshot is provided, using it");
122+
return SafeFuture.completedFuture(depositSnapshotFileLoader.loadDepositSnapshot());
127123
}
128124

129-
if (takeBestDepositSnapshot) {
130-
STATUS_LOG.loadingDepositSnapshotFromDb();
131-
return depositSnapshotStorageLoader
132-
.loadDepositSnapshot()
133-
.thenApply(
134-
storageDepositSnapshotResult -> {
135-
if (storageDepositSnapshotResult.getDepositTreeSnapshot().isPresent()) {
136-
final DepositTreeSnapshot storageSnapshot =
137-
storageDepositSnapshotResult.getDepositTreeSnapshot().get();
138-
STATUS_LOG.onDepositSnapshot(
139-
storageSnapshot.getDepositCount(), storageSnapshot.getExecutionBlockHash());
140-
}
141-
return ObjectUtils.max(storageDepositSnapshotResult, fileDepositSnapshotResult);
142-
});
143-
} else {
144-
return depositSnapshotStorageLoader.loadDepositSnapshot();
145-
}
125+
return depositSnapshotStorageLoader
126+
.loadDepositSnapshot()
127+
.thenApply(
128+
storageDepositSnapshotResult -> {
129+
if (storageDepositSnapshotResult.getDepositTreeSnapshot().isPresent()) {
130+
final DepositTreeSnapshot storageSnapshot =
131+
storageDepositSnapshotResult.getDepositTreeSnapshot().get();
132+
STATUS_LOG.onDepositSnapshot(
133+
storageSnapshot.getDepositCount(), storageSnapshot.getExecutionBlockHash());
134+
return storageDepositSnapshotResult;
135+
}
136+
137+
final LoadDepositSnapshotResult fileDepositSnapshotResult =
138+
depositSnapshotFileLoader.loadDepositSnapshot();
139+
LOG.debug(
140+
"Database deposit snapshot is not present, falling back to the file provided");
141+
return fileDepositSnapshotResult;
142+
});
146143
}
147144

148145
public void stop() {

Diff for: beacon/pow/src/test/java/tech/pegasys/teku/beacon/pow/Eth1DepositManagerTest.java

+52-26
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ void shouldStartWithStoredDepositsChainReorgedToBeShorter() {
362362
final BigInteger headBlockNumber = BigInteger.valueOf(60);
363363
final BigInteger lastReplayedBlock = BigInteger.valueOf(70);
364364
final BigInteger lastReplayedDepositIndex = BigInteger.valueOf(71);
365+
366+
// No deposit tree snapshot loaded, this will be used
365367
when(eth1DepositStorageChannel.replayDepositEvents())
366368
.thenReturn(
367369
SafeFuture.completedFuture(
@@ -383,31 +385,63 @@ void shouldStartWithStoredDepositsChainReorgedToBeShorter() {
383385
}
384386

385387
@Test
386-
void shouldStartFromSnapshotFileWhenProvided() {
388+
void shouldIgnoreSnapshotFileWhenDBSavedVersionProvided() {
387389
final UInt64 deposits = UInt64.valueOf(100);
388390
final BigInteger lastBlockNumber = BigInteger.valueOf(1000);
389391

390-
// DepositTreeSnapshot from file will be used to start from
392+
// This one will be ignored as DB already has a saved version
391393
final DepositTreeSnapshot depositTreeSnapshotFromFile =
392394
dataStructureUtil.randomDepositTreeSnapshot(
393395
deposits.longValue(), UInt64.valueOf(lastBlockNumber));
394396
when(depositSnapshotFileLoader.loadDepositSnapshot())
395397
.thenReturn(LoadDepositSnapshotResult.create(Optional.of(depositTreeSnapshotFromFile)));
396398
when(depositProcessingController.fetchDepositsInRange(any(), any())).thenReturn(COMPLETE);
397399

398-
// This one will be ignored
400+
// DepositTreeSnapshot from DB will be used to start from
401+
final UInt64 dbDepositCount = deposits.plus(50);
402+
final UInt64 dbBlockHeight = UInt64.valueOf(lastBlockNumber).plus(500);
399403
final DepositTreeSnapshot depositTreeSnapshotFromDb =
400-
dataStructureUtil.randomDepositTreeSnapshot(
401-
deposits.plus(50).longValue(), UInt64.valueOf(lastBlockNumber).plus(500));
404+
dataStructureUtil.randomDepositTreeSnapshot(dbDepositCount.longValue(), dbBlockHeight);
402405
when(depositSnapshotStorageLoader.loadDepositSnapshot())
403406
.thenReturn(
404407
SafeFuture.completedFuture(
405408
LoadDepositSnapshotResult.create(Optional.of(depositTreeSnapshotFromDb))));
406409

407410
manager.start();
408411
notifyHeadBlock(lastBlockNumber, MIN_GENESIS_BLOCK_TIMESTAMP + 1000);
412+
verify(depositSnapshotFileLoader, never()).loadDepositSnapshot();
409413
verify(eth1DepositStorageChannel, never()).replayDepositEvents();
410-
verify(eth1EventsChannel).setLatestPublishedDeposit(deposits.decrement());
414+
verify(eth1EventsChannel).setLatestPublishedDeposit(dbDepositCount.decrement());
415+
inOrder
416+
.verify(depositProcessingController)
417+
.startSubscription(dbBlockHeight.bigIntegerValue().add(BigInteger.ONE));
418+
inOrder.verifyNoMoreInteractions();
419+
assertNoUncaughtExceptions();
420+
}
421+
422+
@Test
423+
void shouldTakeSnapshotFileWhenDBSavedVersionNotProvided() {
424+
final UInt64 depositsCount = UInt64.valueOf(100);
425+
final BigInteger lastBlockNumber = BigInteger.valueOf(1000);
426+
427+
// This one will be used as DB empty
428+
final DepositTreeSnapshot depositTreeSnapshotFromFile =
429+
dataStructureUtil.randomDepositTreeSnapshot(
430+
depositsCount.longValue(), UInt64.valueOf(lastBlockNumber));
431+
when(depositSnapshotFileLoader.loadDepositSnapshot())
432+
.thenReturn(LoadDepositSnapshotResult.create(Optional.of(depositTreeSnapshotFromFile)));
433+
when(depositProcessingController.fetchDepositsInRange(any(), any())).thenReturn(COMPLETE);
434+
435+
// DepositTreeSnapshot from DB empty
436+
when(depositSnapshotStorageLoader.loadDepositSnapshot())
437+
.thenReturn(SafeFuture.completedFuture(LoadDepositSnapshotResult.EMPTY));
438+
439+
manager.start();
440+
notifyHeadBlock(lastBlockNumber, MIN_GENESIS_BLOCK_TIMESTAMP + 1000);
441+
verify(depositSnapshotStorageLoader).loadDepositSnapshot();
442+
verify(depositSnapshotFileLoader).loadDepositSnapshot();
443+
verify(eth1DepositStorageChannel, never()).replayDepositEvents();
444+
verify(eth1EventsChannel).setLatestPublishedDeposit(depositsCount.decrement());
411445
inOrder
412446
.verify(depositProcessingController)
413447
.startSubscription(lastBlockNumber.add(BigInteger.ONE));
@@ -444,8 +478,8 @@ void shouldStartFromStorageSnapshotWhenProvided() {
444478
}
445479

446480
@Test
447-
void shouldStartFromBestSnapshotWhenOptionEnabled() {
448-
final Eth1DepositManager manager2 =
481+
void shouldUseCustomDepositSnapshotPathWhenProvided() {
482+
final Eth1DepositManager manager =
449483
new Eth1DepositManager(
450484
config,
451485
eth1Provider,
@@ -460,34 +494,26 @@ void shouldStartFromBestSnapshotWhenOptionEnabled() {
460494
Optional.empty(),
461495
eth1HeadTracker);
462496

463-
final UInt64 deposits = UInt64.valueOf(100);
464-
final BigInteger lastBlockNumberFile = BigInteger.valueOf(1000);
465-
final BigInteger lastBlockNumberStorage = BigInteger.valueOf(2000);
497+
final UInt64 depositsCount = UInt64.valueOf(100);
498+
final BigInteger lastBlockNumber = BigInteger.valueOf(1000);
466499

467-
// DepositTreeSnapshot from file will be loaded
500+
// Custom deposit snapshot path provided, so will be used
468501
final DepositTreeSnapshot depositTreeSnapshotFromFile =
469502
dataStructureUtil.randomDepositTreeSnapshot(
470-
deposits.longValue(), UInt64.valueOf(lastBlockNumberFile));
503+
depositsCount.longValue(), UInt64.valueOf(lastBlockNumber));
471504
when(depositSnapshotFileLoader.loadDepositSnapshot())
472505
.thenReturn(LoadDepositSnapshotResult.create(Optional.of(depositTreeSnapshotFromFile)));
473506
when(depositProcessingController.fetchDepositsInRange(any(), any())).thenReturn(COMPLETE);
474507

475-
// Storage snapshot will be loaded too and compared to the one from file
476-
final DepositTreeSnapshot depositTreeSnapshotFromDb =
477-
dataStructureUtil.randomDepositTreeSnapshot(
478-
deposits.longValue(), UInt64.valueOf(lastBlockNumberStorage));
479-
when(depositSnapshotStorageLoader.loadDepositSnapshot())
480-
.thenReturn(
481-
SafeFuture.completedFuture(
482-
LoadDepositSnapshotResult.create(Optional.of(depositTreeSnapshotFromDb))));
483-
484-
manager2.start();
485-
notifyHeadBlock(BigInteger.valueOf(3000), MIN_GENESIS_BLOCK_TIMESTAMP + 1000);
508+
manager.start();
509+
notifyHeadBlock(lastBlockNumber, MIN_GENESIS_BLOCK_TIMESTAMP + 1000);
510+
verify(depositSnapshotStorageLoader, never()).loadDepositSnapshot();
511+
verify(depositSnapshotFileLoader).loadDepositSnapshot();
486512
verify(eth1DepositStorageChannel, never()).replayDepositEvents();
487-
verify(eth1EventsChannel).setLatestPublishedDeposit(deposits.decrement());
513+
verify(eth1EventsChannel).setLatestPublishedDeposit(depositsCount.decrement());
488514
inOrder
489515
.verify(depositProcessingController)
490-
.startSubscription(lastBlockNumberStorage.add(BigInteger.ONE));
516+
.startSubscription(lastBlockNumber.add(BigInteger.ONE));
491517
inOrder.verifyNoMoreInteractions();
492518
assertNoUncaughtExceptions();
493519
}

Diff for: services/powchain/src/main/java/tech/pegasys/teku/services/powchain/PowchainService.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ public PowchainService(
188188
eth1DepositStorageChannel,
189189
depositSnapshotFileLoader,
190190
depositSnapshotStorageLoader,
191-
depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled(),
191+
depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath().isPresent(),
192192
depositProcessingController,
193193
new MinimumGenesisTimeBlockFinder(config, eth1Provider, eth1DepositContractDeployBlock),
194194
eth1DepositContractDeployBlock,
@@ -203,7 +203,7 @@ private DepositSnapshotFileLoader createDepositSnapshotFileLoader(
203203
if (depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath().isPresent()) {
204204
depositSnapshotFileLoaderBuilder.addRequiredResource(
205205
depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath().get());
206-
} else {
206+
} else if (depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled()) {
207207
depositTreeSnapshotConfiguration
208208
.getCheckpointSyncDepositSnapshotUrl()
209209
.ifPresent(depositSnapshotFileLoaderBuilder::addOptionalResource);

Diff for: services/powchain/src/test/java/tech/pegasys/teku/services/powchain/PowchainServiceTest.java

+32
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public void shouldUseBundledDepositSnapshotPathWhenAvailableAndCustomPathNotPres
125125
.thenReturn(Optional.empty());
126126
when(depositTreeSnapshotConfiguration.getBundledDepositSnapshotPath())
127127
.thenReturn(Optional.of("/foo/bundled"));
128+
when(depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled()).thenReturn(true);
128129

129130
final PowchainService powchainService =
130131
new PowchainService(serviceConfig, powConfig, Optional.of(engineWeb3jClientProvider));
@@ -133,6 +134,20 @@ public void shouldUseBundledDepositSnapshotPathWhenAvailableAndCustomPathNotPres
133134
powchainService, List.of(new DepositSnapshotResource("/foo/bundled", true)));
134135
}
135136

137+
@Test
138+
public void shouldNotUseBundledDepositSnapshotPathWhenDepositSnapshotDisabled() {
139+
when(depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath())
140+
.thenReturn(Optional.empty());
141+
when(depositTreeSnapshotConfiguration.getBundledDepositSnapshotPath())
142+
.thenReturn(Optional.of("/foo/bundled"));
143+
when(depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled()).thenReturn(false);
144+
145+
final PowchainService powchainService =
146+
new PowchainService(serviceConfig, powConfig, Optional.of(engineWeb3jClientProvider));
147+
148+
verifyExpectedOrderOfDepositSnapshotPathResources(powchainService, List.of());
149+
}
150+
136151
@Test
137152
public void shouldUseCheckpointSyncAndBundledDepositSnapshotPath() {
138153
when(depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath())
@@ -141,6 +156,7 @@ public void shouldUseCheckpointSyncAndBundledDepositSnapshotPath() {
141156
.thenReturn(Optional.of("/foo/checkpoint"));
142157
when(depositTreeSnapshotConfiguration.getBundledDepositSnapshotPath())
143158
.thenReturn(Optional.of("/foo/bundled"));
159+
when(depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled()).thenReturn(true);
144160

145161
final PowchainService powchainService =
146162
new PowchainService(serviceConfig, powConfig, Optional.of(engineWeb3jClientProvider));
@@ -152,6 +168,22 @@ public void shouldUseCheckpointSyncAndBundledDepositSnapshotPath() {
152168
new DepositSnapshotResource("/foo/bundled", true)));
153169
}
154170

171+
@Test
172+
public void shouldNotUseCheckpointSyncAndBundledDepositSnapshotPathWhenSnapshotDisabled() {
173+
when(depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath())
174+
.thenReturn(Optional.empty());
175+
when(depositTreeSnapshotConfiguration.getCheckpointSyncDepositSnapshotUrl())
176+
.thenReturn(Optional.of("/foo/checkpoint"));
177+
when(depositTreeSnapshotConfiguration.getBundledDepositSnapshotPath())
178+
.thenReturn(Optional.of("/foo/bundled"));
179+
when(depositTreeSnapshotConfiguration.isBundledDepositSnapshotEnabled()).thenReturn(false);
180+
181+
final PowchainService powchainService =
182+
new PowchainService(serviceConfig, powConfig, Optional.of(engineWeb3jClientProvider));
183+
184+
verifyExpectedOrderOfDepositSnapshotPathResources(powchainService, List.of());
185+
}
186+
155187
@Test
156188
public void shouldUseCustomDepositSnapshotPathEvenWhenCheckpointSyncIsPresent() {
157189
when(depositTreeSnapshotConfiguration.getCustomDepositSnapshotPath())

0 commit comments

Comments
 (0)