Skip to content

Commit 3e79de2

Browse files
authored
Merge pull request #4146 from TheBlueMatt/2025-10-less-panicy-reads
Allow stale `ChannelMonitor`s if we are sure they don't have funds
2 parents 3ce8204 + b1fc759 commit 3e79de2

File tree

2 files changed

+92
-28
lines changed

2 files changed

+92
-28
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,11 +1059,21 @@ impl Readable for IrrevocablyResolvedHTLC {
10591059
/// You MUST ensure that no ChannelMonitors for a given channel anywhere contain out-of-date
10601060
/// information and are actively monitoring the chain.
10611061
///
1062-
/// Note that the deserializer is only implemented for (BlockHash, ChannelMonitor), which
1063-
/// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
1064-
/// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the
1065-
/// returned block hash and the the current chain and then reconnecting blocks to get to the
1066-
/// best chain) upon deserializing the object!
1062+
/// Like the [`ChannelManager`], deserialization is implemented for `(BlockHash, ChannelMonitor)`,
1063+
/// providing you with the last block hash which was connected before shutting down. You must begin
1064+
/// syncing the chain from that point, disconnecting and connecting blocks as required to get to
1065+
/// the best chain on startup. Note that all [`ChannelMonitor`]s passed to a [`ChainMonitor`] must
1066+
/// by synced as of the same block, so syncing must happen prior to [`ChainMonitor`]
1067+
/// initialization.
1068+
///
1069+
/// For those loading potentially-ancient [`ChannelMonitor`]s, deserialization is also implemented
1070+
/// for `Option<(BlockHash, ChannelMonitor)>`. LDK can no longer deserialize a [`ChannelMonitor`]
1071+
/// that was first created in LDK prior to 0.0.110 and last updated prior to LDK 0.0.119. In such
1072+
/// cases, the `Option<(..)>` deserialization option may return `Ok(None)` rather than failing to
1073+
/// deserialize, allowing you to differentiate between the two cases.
1074+
///
1075+
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
1076+
/// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
10671077
pub struct ChannelMonitor<Signer: EcdsaChannelSigner> {
10681078
pub(crate) inner: Mutex<ChannelMonitorImpl<Signer>>,
10691079
}
@@ -6251,6 +6261,18 @@ const MAX_ALLOC_SIZE: usize = 64 * 1024;
62516261

62526262
impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP)>
62536263
for (BlockHash, ChannelMonitor<SP::EcdsaSigner>)
6264+
{
6265+
fn read<R: io::Read>(reader: &mut R, args: (&'a ES, &'b SP)) -> Result<Self, DecodeError> {
6266+
match <Option<Self>>::read(reader, args) {
6267+
Ok(Some(res)) => Ok(res),
6268+
Ok(None) => Err(DecodeError::UnknownRequiredFeature),
6269+
Err(e) => Err(e),
6270+
}
6271+
}
6272+
}
6273+
6274+
impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP)>
6275+
for Option<(BlockHash, ChannelMonitor<SP::EcdsaSigner>)>
62546276
{
62556277
#[rustfmt::skip]
62566278
fn read<R: io::Read>(reader: &mut R, args: (&'a ES, &'b SP)) -> Result<Self, DecodeError> {
@@ -6528,11 +6550,6 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
65286550
}
65296551

65306552
let channel_id = channel_id.unwrap_or(ChannelId::v1_from_funding_outpoint(outpoint));
6531-
if counterparty_node_id.is_none() {
6532-
panic!("Found monitor for channel {} with no updates since v0.0.118.\
6533-
These monitors are no longer supported.\
6534-
To continue, run a v0.1 release, send/route a payment over the channel or close it.", channel_id);
6535-
}
65366553

65376554
let (current_holder_commitment_tx, current_holder_htlc_data) = {
65386555
let holder_commitment_tx = onchain_tx_handler.current_holder_commitment_tx();
@@ -6586,7 +6603,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
65866603
(None, None)
65876604
};
65886605

6589-
Ok((best_block.block_hash, ChannelMonitor::from_impl(ChannelMonitorImpl {
6606+
let dummy_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
6607+
let monitor = ChannelMonitor::from_impl(ChannelMonitorImpl {
65906608
funding: FundingScope {
65916609
channel_parameters,
65926610

@@ -6646,7 +6664,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
66466664
spendable_txids_confirmed: spendable_txids_confirmed.unwrap(),
66476665

66486666
best_block,
6649-
counterparty_node_id: counterparty_node_id.unwrap(),
6667+
counterparty_node_id: counterparty_node_id.unwrap_or(dummy_node_id),
66506668
initial_counterparty_commitment_info,
66516669
initial_counterparty_commitment_tx,
66526670
balances_empty_height,
@@ -6658,7 +6676,20 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
66586676
alternative_funding_confirmed,
66596677

66606678
written_by_0_1_or_later,
6661-
})))
6679+
});
6680+
6681+
if counterparty_node_id.is_none() {
6682+
if (holder_tx_signed || lockdown_from_offchain) && monitor.get_claimable_balances().is_empty() {
6683+
// If the monitor is no longer readable, but it is a candidate for archiving,
6684+
// return Ok(None) to allow it to be skipped and not loaded.
6685+
return Ok(None);
6686+
} else {
6687+
panic!("Found monitor for channel {channel_id} with no updates since v0.0.118. \
6688+
These monitors are no longer supported. \
6689+
To continue, run a v0.1 release, send/route a payment over the channel or close it.");
6690+
}
6691+
}
6692+
Ok(Some((best_block.block_hash, monitor)))
66626693
}
66636694
}
66646695

lightning/src/util/persist.rs

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,15 @@ where
372372
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
373373
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
374374
)? {
375-
match <(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>::read(
375+
match <Option<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>>::read(
376376
&mut io::Cursor::new(kv_store.read(
377377
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
378378
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
379379
&stored_key,
380380
)?),
381381
(&*entropy_source, &*signer_provider),
382382
) {
383-
Ok((block_hash, channel_monitor)) => {
383+
Ok(Some((block_hash, channel_monitor))) => {
384384
let monitor_name = MonitorName::from_str(&stored_key)?;
385385
if channel_monitor.persistence_key() != monitor_name {
386386
return Err(io::Error::new(
@@ -391,6 +391,7 @@ where
391391

392392
res.push((block_hash, channel_monitor));
393393
},
394+
Ok(None) => {},
394395
Err(_) => {
395396
return Err(io::Error::new(
396397
io::ErrorKind::InvalidData,
@@ -783,9 +784,12 @@ where
783784
let secondary = CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE;
784785
let monitor_list = self.0.kv_store.list(primary, secondary).await?;
785786
let mut res = Vec::with_capacity(monitor_list.len());
786-
// TODO: Parallelize this loop
787787
for monitor_key in monitor_list {
788-
res.push(self.read_channel_monitor_with_updates(monitor_key.as_str()).await?)
788+
let result =
789+
self.0.maybe_read_channel_monitor_with_updates(monitor_key.as_str()).await?;
790+
if let Some(read_res) = result {
791+
res.push(read_res);
792+
}
789793
}
790794
Ok(res)
791795
}
@@ -923,8 +927,29 @@ where
923927
&self, monitor_key: &str,
924928
) -> Result<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), io::Error>
925929
{
930+
match self.maybe_read_channel_monitor_with_updates(monitor_key).await? {
931+
Some(res) => Ok(res),
932+
None => Err(io::Error::new(
933+
io::ErrorKind::InvalidData,
934+
"ChannelMonitor was stale, with no updates since LDK 0.0.118. \
935+
It cannot be read by modern versions of LDK, though also does not contain any funds left to sweep. \
936+
You should manually delete it instead",
937+
)),
938+
}
939+
}
940+
941+
async fn maybe_read_channel_monitor_with_updates(
942+
&self, monitor_key: &str,
943+
) -> Result<
944+
Option<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>,
945+
io::Error,
946+
> {
926947
let monitor_name = MonitorName::from_str(monitor_key)?;
927-
let (block_hash, monitor) = self.read_monitor(&monitor_name, monitor_key).await?;
948+
let read_res = self.maybe_read_monitor(&monitor_name, monitor_key).await?;
949+
let (block_hash, monitor) = match read_res {
950+
Some(res) => res,
951+
None => return Ok(None),
952+
};
928953
let mut current_update_id = monitor.get_latest_update_id();
929954
// TODO: Parallelize this loop by speculatively reading a batch of updates
930955
loop {
@@ -955,14 +980,16 @@ where
955980
io::Error::new(io::ErrorKind::Other, "Monitor update failed")
956981
})?;
957982
}
958-
Ok((block_hash, monitor))
983+
Ok(Some((block_hash, monitor)))
959984
}
960985

961986
/// Read a channel monitor.
962-
async fn read_monitor(
987+
async fn maybe_read_monitor(
963988
&self, monitor_name: &MonitorName, monitor_key: &str,
964-
) -> Result<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), io::Error>
965-
{
989+
) -> Result<
990+
Option<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>,
991+
io::Error,
992+
> {
966993
let primary = CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE;
967994
let secondary = CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE;
968995
let monitor_bytes = self.kv_store.read(primary, secondary, monitor_key).await?;
@@ -971,11 +998,12 @@ where
971998
if monitor_cursor.get_ref().starts_with(MONITOR_UPDATING_PERSISTER_PREPEND_SENTINEL) {
972999
monitor_cursor.set_position(MONITOR_UPDATING_PERSISTER_PREPEND_SENTINEL.len() as u64);
9731000
}
974-
match <(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>::read(
1001+
match <Option<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>>::read(
9751002
&mut monitor_cursor,
9761003
(&*self.entropy_source, &*self.signer_provider),
9771004
) {
978-
Ok((blockhash, channel_monitor)) => {
1005+
Ok(None) => Ok(None),
1006+
Ok(Some((blockhash, channel_monitor))) => {
9791007
if channel_monitor.persistence_key() != *monitor_name {
9801008
log_error!(
9811009
self.logger,
@@ -987,7 +1015,7 @@ where
9871015
"ChannelMonitor was stored under the wrong key",
9881016
))
9891017
} else {
990-
Ok((blockhash, channel_monitor))
1018+
Ok(Some((blockhash, channel_monitor)))
9911019
}
9921020
},
9931021
Err(e) => {
@@ -1027,9 +1055,14 @@ where
10271055
let monitor_keys = self.kv_store.list(primary, secondary).await?;
10281056
for monitor_key in monitor_keys {
10291057
let monitor_name = MonitorName::from_str(&monitor_key)?;
1030-
let (_, current_monitor) = self.read_monitor(&monitor_name, &monitor_key).await?;
1031-
let latest_update_id = current_monitor.get_latest_update_id();
1032-
self.cleanup_stale_updates_for_monitor_to(&monitor_key, latest_update_id).await?;
1058+
let maybe_monitor = self.maybe_read_monitor(&monitor_name, &monitor_key).await?;
1059+
if let Some((_, current_monitor)) = maybe_monitor {
1060+
let latest_update_id = current_monitor.get_latest_update_id();
1061+
self.cleanup_stale_updates_for_monitor_to(&monitor_key, latest_update_id).await?;
1062+
} else {
1063+
// TODO: Also clean up super stale monitors (created pre-0.0.110 and last updated
1064+
// pre-0.0.119).
1065+
}
10331066
}
10341067
Ok(())
10351068
}

0 commit comments

Comments
 (0)