Add a fallback pivot strategy when the safe block does not change for a long time (#8395)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
Fabio Di Fabio
2025-03-11 11:56:51 +01:00
committed by GitHub
parent 90db4872a4
commit 011b52d10c
2 changed files with 50 additions and 6 deletions

View File

@@ -44,6 +44,7 @@
### Bug fixes
- Add missing RPC method `debug_accountRange` to `RpcMethod.java` so this method can be used with `--rpc-http-api-method-no-auth` [#8153](https://github.com/hyperledger/besu/issues/8153)
- Add a fallback pivot strategy when the safe block does not change for a long time, to make possible to complete the initial sync in case the chain is not finalizing [#8395](https://github.com/hyperledger/besu/pull/8395)
## 25.2.2 hotfix
- Pectra - Sepolia: Fix for deposit contract log decoding [#8383](https://github.com/hyperledger/besu/pull/8383)

View File

@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByH
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -41,6 +42,9 @@ import org.slf4j.LoggerFactory;
public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
private static final Logger LOG = LoggerFactory.getLogger(PivotSelectorFromSafeBlock.class);
private static final long NO_FCU_RECEIVED_LOGGING_THRESHOLD = Duration.ofMinutes(1).toMillis();
private static final long UNCHANGED_PIVOT_BLOCK_FALLBACK_INTERVAL =
Duration.ofMinutes(7).toMillis();
private final ProtocolContext protocolContext;
private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext;
@@ -50,8 +54,12 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
private final Supplier<Optional<ForkchoiceEvent>> forkchoiceStateSupplier;
private final Runnable cleanupAction;
private long lastNoFcuReceivedInfoLog = System.currentTimeMillis();
private static final long NO_FCU_RECEIVED_LOGGING_THRESHOLD = 60000L;
private volatile long lastNoFcuReceivedInfoLog = System.currentTimeMillis();
private volatile long lastPivotBlockChange = System.currentTimeMillis();
private volatile Hash lastSafeBlockHash = Hash.ZERO;
private volatile Hash fallbackBlockHash;
private volatile Hash lastFallbackBlockHash;
private volatile boolean inFallbackMode = false;
private volatile Optional<BlockHeader> maybeCachedHeadBlockHeader = Optional.empty();
public PivotSelectorFromSafeBlock(
@@ -76,11 +84,38 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
@Override
public Optional<FastSyncState> selectNewPivotBlock() {
final Optional<ForkchoiceEvent> maybeForkchoice = forkchoiceStateSupplier.get();
final var now = System.currentTimeMillis();
if (maybeForkchoice.isPresent() && maybeForkchoice.get().hasValidSafeBlockHash()) {
return Optional.of(selectLastSafeBlockAsPivot(maybeForkchoice.get().getSafeBlockHash()));
final var safeBlockHash = maybeForkchoice.get().getSafeBlockHash();
// if the safe has changed just return it and reset the timer and save the current head as
// fallback
if (!safeBlockHash.equals(lastSafeBlockHash)) {
lastSafeBlockHash = safeBlockHash;
lastPivotBlockChange = now;
inFallbackMode = false;
fallbackBlockHash = maybeForkchoice.get().getHeadBlockHash();
return Optional.of(selectLastSafeBlockAsPivot(safeBlockHash));
}
// otherwise verify if we need to fallback to a previous head block
if (lastPivotBlockChange + UNCHANGED_PIVOT_BLOCK_FALLBACK_INTERVAL < now) {
lastPivotBlockChange = now;
inFallbackMode = true;
lastFallbackBlockHash = fallbackBlockHash;
final var fallbackPivot = selectFallbackBlockAsPivot(fallbackBlockHash);
fallbackBlockHash = maybeForkchoice.get().getHeadBlockHash();
return Optional.of(fallbackPivot);
}
// if not enough time has passed the return again the previous value
return Optional.of(
selectLastSafeBlockAsPivot(inFallbackMode ? lastFallbackBlockHash : lastSafeBlockHash));
}
if (lastNoFcuReceivedInfoLog + NO_FCU_RECEIVED_LOGGING_THRESHOLD < System.currentTimeMillis()) {
lastNoFcuReceivedInfoLog = System.currentTimeMillis();
if (lastNoFcuReceivedInfoLog + NO_FCU_RECEIVED_LOGGING_THRESHOLD < now) {
lastNoFcuReceivedInfoLog = now;
LOG.info(
"Waiting for consensus client, this may be because your consensus client is still syncing");
}
@@ -99,6 +134,14 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
return new FastSyncState(safeHash);
}
private FastSyncState selectFallbackBlockAsPivot(final Hash fallbackBlockHash) {
LOG.debug(
"Safe block not changed in the last {} min, using a previous head block {} as fallback",
UNCHANGED_PIVOT_BLOCK_FALLBACK_INTERVAL / 60,
fallbackBlockHash);
return new FastSyncState(fallbackBlockHash);
}
@Override
public void close() {
cleanupAction.run();
@@ -188,7 +231,7 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
LOG.debug("Error downloading block header by hash {}", hash);
} else {
LOG.atDebug()
.setMessage("Successfully downloaded pivot block header by hash {}")
.setMessage("Successfully downloaded block header by hash {}")
.addArgument(blockHeader::toLogString)
.log();
}