Add missing `OffersMessageHandler::best_block` updating
What changed, and why it matters
This commit fixes a bug where a piece of data called `best_block` was not being updated when new blocks arrived. This data is used when creating private, one-time Lightning payment routes. If it goes stale for more than two weeks, the software could build payment routes that other nodes consider expired or invalid, causing payments to fail. The fix simply updates `best_block` whenever a new block is seen.
Upgrade to a release containing this commit if you run a long-lived LDK node that processes BOLT 12 offers. Until patched, a node restart refreshes `best_block`, so scheduled restarts within two weeks can mitigate the issue. Monitor for failed BOLT 12 payments with invalid-blinded-path errors.
Security signals we found
Missing state update in chain-tip handler
Potential construction of invalid/expired blinded payment paths
Payment path validity depends on fresh best-block data
Bug window: approximately two weeks without restart
No explicit authentication/authorization bypass
Evidence from the diff
The OffersMessageFlow::best_block_updated method in lightning/src/offers/flow.rs was updating highest_seen_timestamp but not writing the new block hash and height to self.best_block. best_block is used to construct short-lived blinded payment paths; if it lags the chain tip by more than the roughly-two-week expiry window, the resulting paths may reference an expired block height and be rejected. The patch adds the missing write: *self.best_block.write().unwrap() = BestBlock::new(header.block_hash(), height);.
Changed components
lightning/src/offers/flow.rsOffersMessageFlow::best_block_updatedBOLT 12 offer/blinded path constructionInspect captured patch +3 / −1
diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs
index 79e2332..901866f 100644
--- a/lightning/src/offers/flow.rs
+++ b/lightning/src/offers/flow.rs
@@ -183,10 +183,12 @@ impl<MR: MessageRouter, L: Logger> OffersMessageFlow<MR, L> {
///
/// Must be called whenever a new chain tip becomes available. May be skipped
/// for intermediary blocks.
- pub fn best_block_updated(&self, header: &Header, _height: u32) {
+ pub fn best_block_updated(&self, header: &Header, height: u32) {
let timestamp = &self.highest_seen_timestamp;
let block_time = header.time as usize;
+ *self.best_block.write().unwrap() = BestBlock::new(header.block_hash(), height);
+
loop {
// Update timestamp to be the max of its current value and the block
// timestamp. This should keep us close to the current time without relying on
Why this scored 59/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.