Use the header cache across listeners during initial disconnect
What changed, and why it matters
This commit is a performance optimization for the Lightning Dev Kit's block synchronization code. It makes the software reuse a cache of block headers when comparing chain states across multiple listeners, rather than repeatedly asking the Bitcoin node for the same headers. The change reduces startup sync time from about 500ms to under 150ms. It is not a security fix and does not appear to introduce a meaningful security vulnerability.
No security action required. Treat as a normal performance optimization. If desired, reviewers can verify that `insert_during_diff` eviction logic is equivalent to `block_connected` and that cached headers are not used for consensus-critical validation decisions.
Security signals we found
No security-relevant keywords in commit title or message
Change is framed as a performance improvement (500ms -> 150ms)
Cache eviction policy mirrors existing `block_connected` behavior
No new external inputs or trust boundaries introduced
No changes to authentication, cryptography, or network protocol handling
Evidence from the diff
The patch adds HeaderCache::insert_during_diff and modifies ChainNotifier::find_difference_from_best_block to populate the header cache while resolving previous best-block headers during chain diff operations. The cache eviction policy is identical to block_connected: retain headers within HEADER_CACHE_LIMIT of the best known height. The method is marked pub(crate) and used only internally during initial synchronization.
Changed components
lightning-block-sync/src/lib.rsHeaderCacheChainNotifier::find_difference_from_best_blockinit::synchronize_listenersInspect captured patch +18 / −2
diff --git a/lightning-block-sync/src/lib.rs b/lightning-block-sync/src/lib.rs
index c2590f0..c5bc1d0 100644
--- a/lightning-block-sync/src/lib.rs
+++ b/lightning-block-sync/src/lib.rs
@@ -206,7 +206,6 @@ impl HeaderCache {
self.headers.get(block_hash)
}
-
/// Called when a block has been connected to the best chain to ensure it is available to be
/// disconnected later if needed.
pub(crate) fn block_connected(
@@ -219,6 +218,19 @@ impl HeaderCache {
self.headers.retain(|_, header| header.height >= cutoff_height);
}
+ /// Inserts the given block header during a find_difference operation, implying it might not be
+ /// the best header.
+ pub(crate) fn insert_during_diff(
+ &mut self, block_hash: BlockHash, block_header: ValidatedBlockHeader,
+ ) {
+ self.headers.insert(block_hash, block_header);
+
+ // Remove headers older than our newest header minus a week.
+ let best_height = self.headers.iter().map(|(_, header)| header.height).max().unwrap_or(0);
+ let cutoff_height = best_height.saturating_sub(HEADER_CACHE_LIMIT);
+ self.headers.retain(|_, header| header.height >= cutoff_height);
+ }
+
/// Called when blocks have been disconnected from the best chain. Only the fork point
/// (best common ancestor) is provided.
///
@@ -350,8 +362,11 @@ impl<'a, L: chain::Listen + ?Sized> ChainNotifier<'a, L> {
///
/// First resolves `prev_best_block` to a `ValidatedBlockHeader` using the `previous_blocks`
/// field as fallback if needed, then finds the common ancestor.
+ ///
+ /// Updates the header cache as it goes, tracking headers needed to find the diff to reuse for
+ /// other objects that might need similar headers.
async fn find_difference_from_best_block<P: Poll>(
- &self, current_header: ValidatedBlockHeader, prev_best_block: BestBlock,
+ &mut self, current_header: ValidatedBlockHeader, prev_best_block: BestBlock,
chain_poller: &mut P,
) -> BlockSourceResult<ChainDifference> {
// Try to resolve the header for the previous best block. First try the block_hash,
@@ -376,6 +391,7 @@ impl<'a, L: chain::Listen + ?Sized> ChainNotifier<'a, L> {
)?;
if let Ok(header) = chain_poller.get_header(block_hash, Some(height)).await {
found_header = Some(header);
+ self.header_cache.insert_during_diff(*block_hash, header);
break;
}
}
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.