Drop `OutputSweeper` non-`BestBlock` `Readable` implementation
What changed, and why it matters
This commit removes an older, less-safe way to restore the OutputSweeper object from disk. The old method let users load it without providing the current blockchain tip, which could leave the sweeper unaware of recent blocks and potentially miss on-chain events it needs to react to. The remaining method forces callers to supply the latest 'best block' so the sweeper can resync on startup, matching how other critical components already work. It is a hardening/correctness change rather than a clear-cut remote exploit fix.
Treat as a defensive hardening patch. Users and downstream maintainers should migrate any code that called the old OutputSweeper::read path to the (BestBlock, OutputSweeper) return path and ensure the sweeper is registered and synced against the current chain tip on startup. No emergency response is indicated by the diff alone.
Security signals we found
Removed deserialization path that relied on persisted best_block without external chain-tip verification
Forces resync of a Confirm/Listen client on startup by requiring BestBlock argument
Prevents potential missed on-chain events due to stale chain tip after restore
Consistency hardening with ChannelMonitor/ChannelManager deserialization patterns
Evidence from the diff
The deleted ReadableArgs implementation deserialized OutputSweeper directly from (B, E, Option
Changed components
lightning/src/util/sweep.rsOutputSweeper deserialization (ReadableArgs)Confirm/Listen client resync pathInspect captured patch +0 / −49
diff --git a/lightning/src/util/sweep.rs b/lightning/src/util/sweep.rs
index e193000..efeb059 100644
--- a/lightning/src/util/sweep.rs
+++ b/lightning/src/util/sweep.rs
@@ -827,55 +827,6 @@ pub enum SpendingDelay {
},
}
-impl<B: Deref, D: Deref, E: Deref, F: Deref, K: Deref, L: Deref, O: Deref>
- ReadableArgs<(B, E, Option<F>, O, D, K, L)> for OutputSweeper<B, D, E, F, K, L, O>
-where
- B::Target: BroadcasterInterface,
- D::Target: ChangeDestinationSource,
- E::Target: FeeEstimator,
- F::Target: Filter + Sync + Send,
- K::Target: KVStore,
- L::Target: Logger,
- O::Target: OutputSpender,
-{
- #[inline]
- fn read<R: io::Read>(
- reader: &mut R, args: (B, E, Option<F>, O, D, K, L),
- ) -> Result<Self, DecodeError> {
- let (
- broadcaster,
- fee_estimator,
- chain_data_source,
- output_spender,
- change_destination_source,
- kv_store,
- logger,
- ) = args;
- let state = SweeperState::read(reader)?;
- let best_block = state.best_block;
-
- if let Some(filter) = chain_data_source.as_ref() {
- for output_info in &state.outputs {
- let watched_output = output_info.to_watched_output(best_block.block_hash);
- filter.register_output(watched_output);
- }
- }
-
- let sweeper_state = Mutex::new(state);
- Ok(Self {
- sweeper_state,
- pending_sweep: AtomicBool::new(false),
- broadcaster,
- fee_estimator,
- chain_data_source,
- output_spender,
- change_destination_source,
- kv_store,
- logger,
- })
- }
-}
-
impl<B: Deref, D: Deref, E: Deref, F: Deref, K: Deref, L: Deref, O: Deref>
ReadableArgs<(B, E, Option<F>, O, D, K, L)> for (BestBlock, OutputSweeper<B, D, E, F, K, L, O>)
where
Why this scored 42/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.