Q: When do we trigger it?
Q: Describe the algorithm
https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#specification-1
forkchoiceState.headBlockHash
references an unknown payload or a payload that can't be validated because data that are requisite for the validation is missing. The sync process is specified in the Sync section.https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#specification
https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#sync
In the context of this specification, the sync is understood as the process of obtaining data required to validate a payload. The sync process may consist of the following stages:
Note: Each of these stages is optional. Exact behavior of client software during the sync process is implementation dependent.
https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#message-ordering
Consensus Layer client software MUST respect the order of the corresponding fork choice update events when making calls to the engine_forkchoiceUpdated
method.
Execution Layer client software MUST process engine_forkchoiceUpdated
method calls
in the same order as they have been received.
We start a new backwards sync (BWS) session on both engine_forkchoiceUpdated (fCU) and engine_newPayload (nP).
AbstractEngineForkchoiceUpdated.java
final Optional<BlockHeader> maybeNewHead =
mergeCoordinator.getOrSyncHeadByHash(forkChoice.getHeadBlockHash(),
forkChoice.getFinalizedBlockHash());
if (maybeNewHead.isEmpty()) {
return syncingResponse(requestId, forkChoice);
}
AbstractEngineNewPayload.java
final Optional<BlockHeader> maybeParentHeader =
protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash());
// ...
if (maybeParentHeader.isEmpty()) {
LOG.atDebug()
.setMessage("Parent of block {} is not present, append it to backward sync")
.addArgument(block::toLogString)
.log();
mergeCoordinator.appendNewPayloadToSync(block);
return respondWith(reqId, blockParam, null, SYNCING);
}
MergeCoordinator.java
@Override
public Optional<BlockHeader> getOrSyncHeadByHash(final Hash headHash, final Hash finalizedHash) {
final var chain = protocolContext.getBlockchain();
final var maybeHeadHeader = chain.getBlockHeader(headHash);
if (maybeHeadHeader.isPresent()) {
LOG.atDebug()
.setMessage("BlockHeader {} is already present")
.addArgument(maybeHeadHeader.get()::toLogString)
.log();
} else {
LOG.atDebug()
.setMessage("Appending new head block hash {} to backward sync")
.addArgument(headHash::toHexString)
.log();
backwardSyncContext.maybeUpdateTargetHeight(headHash);
backwardSyncContext
.syncBackwardsUntil(headHash)
.thenRun(() -> updateFinalized(finalizedHash));
}
return maybeHeadHeader;
}
@Override
public CompletableFuture<Void> appendNewPayloadToSync(final Block newPayload) {
return backwardSyncContext.syncBackwardsUntil(newPayload);
}
BackwardSyncContext
is the entry point and manages the session.BackwardChain
is the data structure, where chainHead is the oldest block.hashesToAppend
is Deque representing the work queue (one per session?)isTrusted
means "do we have it stored?" (Maybe "trust" is because it came from the CL).BackwardSyncAlgorithm
consists of CompletableFuture
Steps composed recursively in a State Pattern.(WorldStateDownload || FastImportBlocks) -> WorldStateHeal -> BWS
BackwardSyncContext | Starting a new backward sync session
BackwardSyncStep | Backward sync phase 1 of 2 completed, downloaded a total of 200 headers. Peers: 8
BackwardSyncContext | Backward sync phase 2 of 2, 2.63% completed, imported 1 blocks of at least 38 (current head 3743023, target head 3743060). Peers: 2
BackwardSyncContext | Backward sync phase 2 of 2, 43.59% completed, imported 17 blocks of at least 39 (current head 3743039, target head 3743061). Peers: 2
BackwardSyncContext | Backward sync phase 2 of 2, 97.50% completed, imported 39 blocks of at least 40 (current head 3743061, target head 3743062). Peers: 3
BackwardSyncContext | Backward sync phase 2 of 2 completed, imported a total of 40 blocks. Peers: 2
BackwardSyncAlgorithm | Current backward sync session is done