Skip to content

Commit 3b2b357

Browse files
committed
Stop using a constant for monitor update_ids after closure
Because `ChannelManager` doesn't have a corresponding `Channel` after the channels are closed, we'd always used an `update_id` of `u64::MAX` for any `ChannelMonitorUpdate`s we need to build after the channel is closed. This completely breaks the abstraction of `update_id`s and leaks into persistence logic - because we might have more than one `ChannelMonitorUpdate` with the same (`u64::MAX`) value, suddenly instead of being able to safely use `update_id` as IDs, the `MonitorUpdatingPersister` has to have special logic to handle this. Worse, because we don't have a unique ID with which to refer to post-close `ChannelMonitorUpdate`s we cannot track when they complete async persistence. This means we cannot properly support async persist for forwarded payments where the inbound edge has hit the chain prior to the preimage coming to us. Here we rectify this by using consistent `update_id`s even after a channel has closed. In order to do so we have to keep some state for all channels for which the `ChannelMonitor` has not been archived (after which point we can be confident we will not need to update them). While this violates our long-standing policy of having no state at all in `ChannelManager`s for closed channels, its only a `(ChannelId, u64)` pair per channel, so shouldn't be problematic for any of our users (as they already store a whole honkin `ChannelMonitor` for these channels anyway). While limited changes are made to the connection-count-limiting logic, reviewers should carefully analyze the interactions the new map created here has with that logic.
1 parent a62a469 commit 3b2b357

File tree

7 files changed

+250
-191
lines changed

7 files changed

+250
-191
lines changed

lightning-persister/src/test_utils.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use lightning::chain::channelmonitor::CLOSED_CHANNEL_UPDATE_ID;
21
use lightning::events::ClosureReason;
32
use lightning::ln::functional_test_utils::{
43
connect_block, create_announced_chan_between_nodes, create_chanmon_cfgs, create_dummy_block,
@@ -168,5 +167,5 @@ pub(crate) fn do_test_store<K: KVStore>(store_0: &K, store_1: &K) {
168167
check_added_monitors!(nodes[1], 1);
169168

170169
// Make sure everything is persisted as expected after close.
171-
check_persisted_data!(CLOSED_CHANNEL_UPDATE_ID);
170+
check_persisted_data!(11);
172171
}

lightning/src/chain/channelmonitor.rs

+27-30
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,9 @@ pub struct ChannelMonitorUpdate {
8989
/// [`ChannelMonitorUpdateStatus::InProgress`] have been applied to all copies of a given
9090
/// ChannelMonitor when ChannelManager::channel_monitor_updated is called.
9191
///
92-
/// The only instances we allow where update_id values are not strictly increasing have a
93-
/// special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. This update ID is used for updates that
94-
/// will force close the channel by broadcasting the latest commitment transaction or
95-
/// special post-force-close updates, like providing preimages necessary to claim outputs on the
96-
/// broadcast commitment transaction. See its docs for more details.
92+
/// Note that for [`ChannelMonitorUpdate]`s generated on LDK versions prior to 0.1 after the
93+
/// channel was closed, this value may be [`u64::MAX`]. In that case, multiple updates may
94+
/// appear with the same ID, and all should be replayed.
9795
///
9896
/// [`ChannelMonitorUpdateStatus::InProgress`]: super::ChannelMonitorUpdateStatus::InProgress
9997
pub update_id: u64,
@@ -104,16 +102,6 @@ pub struct ChannelMonitorUpdate {
104102
pub channel_id: Option<ChannelId>,
105103
}
106104

107-
/// The update ID used for a [`ChannelMonitorUpdate`] that is either:
108-
///
109-
/// (1) attempting to force close the channel by broadcasting our latest commitment transaction or
110-
/// (2) providing a preimage (after the channel has been force closed) from a forward link that
111-
/// allows us to spend an HTLC output on this channel's (the backward link's) broadcasted
112-
/// commitment transaction.
113-
///
114-
/// No other [`ChannelMonitorUpdate`]s are allowed after force-close.
115-
pub const CLOSED_CHANNEL_UPDATE_ID: u64 = core::u64::MAX;
116-
117105
impl Writeable for ChannelMonitorUpdate {
118106
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
119107
write_ver_prefix!(w, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
@@ -1553,6 +1541,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
15531541

15541542
/// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this
15551543
/// ChannelMonitor.
1544+
///
1545+
/// Note that for channels closed prior to LDK 0.1, this may return [`u64::MAX`].
15561546
pub fn get_latest_update_id(&self) -> u64 {
15571547
self.inner.lock().unwrap().get_latest_update_id()
15581548
}
@@ -3116,11 +3106,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
31163106
F::Target: FeeEstimator,
31173107
L::Target: Logger,
31183108
{
3119-
if self.latest_update_id == CLOSED_CHANNEL_UPDATE_ID && updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
3120-
log_info!(logger, "Applying post-force-closed update to monitor {} with {} change(s).",
3109+
if self.latest_update_id == u64::MAX && updates.update_id == u64::MAX {
3110+
log_info!(logger, "Applying pre-0.1 post-force-closed update to monitor {} with {} change(s).",
31213111
log_funding_info!(self), updates.updates.len());
3122-
} else if updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
3123-
log_info!(logger, "Applying force close update to monitor {} with {} change(s).",
3112+
} else if updates.update_id == u64::MAX {
3113+
log_info!(logger, "Applying pre-0.1 force close update to monitor {} with {} change(s).",
31243114
log_funding_info!(self), updates.updates.len());
31253115
} else {
31263116
log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} change(s).",
@@ -3143,14 +3133,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
31433133
// The `ChannelManager` may also queue redundant `ChannelForceClosed` updates if it still
31443134
// thinks the channel needs to have its commitment transaction broadcast, so we'll allow
31453135
// them as well.
3146-
if updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
3136+
if updates.update_id == u64::MAX || self.lockdown_from_offchain {
31473137
assert_eq!(updates.updates.len(), 1);
31483138
match updates.updates[0] {
31493139
ChannelMonitorUpdateStep::ChannelForceClosed { .. } => {},
31503140
// We should have already seen a `ChannelForceClosed` update if we're trying to
31513141
// provide a preimage at this point.
31523142
ChannelMonitorUpdateStep::PaymentPreimage { .. } =>
3153-
debug_assert_eq!(self.latest_update_id, CLOSED_CHANNEL_UPDATE_ID),
3143+
debug_assert!(self.lockdown_from_offchain),
31543144
_ => {
31553145
log_error!(logger, "Attempted to apply post-force-close ChannelMonitorUpdate of type {}", updates.updates[0].variant_name());
31563146
panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage");
@@ -3230,17 +3220,24 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32303220
self.counterparty_commitment_txs_from_update(updates);
32313221
}
32323222

3233-
// If the updates succeeded and we were in an already closed channel state, then there's no
3234-
// need to refuse any updates we expect to receive afer seeing a confirmed commitment.
3235-
if ret.is_ok() && updates.update_id == CLOSED_CHANNEL_UPDATE_ID && self.latest_update_id == updates.update_id {
3236-
return Ok(());
3237-
}
3238-
32393223
self.latest_update_id = updates.update_id;
32403224

3241-
// Refuse updates after we've detected a spend onchain, but only if we haven't processed a
3242-
// force closed monitor update yet.
3243-
if ret.is_ok() && self.funding_spend_seen && self.latest_update_id != CLOSED_CHANNEL_UPDATE_ID {
3225+
// Refuse updates after we've detected a spend onchain (or are otherwise closed), but only
3226+
// if the update isn't the kind of update we expect to see after channel closure.
3227+
let mut is_pre_close_update = false;
3228+
for update in updates.updates.iter() {
3229+
match update {
3230+
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. }
3231+
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. }
3232+
|ChannelMonitorUpdateStep::ShutdownScript { .. }
3233+
|ChannelMonitorUpdateStep::CommitmentSecret { .. } =>
3234+
is_pre_close_update = true,
3235+
ChannelMonitorUpdateStep::PaymentPreimage { .. } => {},
3236+
ChannelMonitorUpdateStep::ChannelForceClosed { .. } => {},
3237+
}
3238+
}
3239+
3240+
if ret.is_ok() && (self.funding_spend_seen || self.lockdown_from_offchain) && is_pre_close_update {
32443241
log_error!(logger, "Refusing Channel Monitor Update as counterparty attempted to update commitment after funding was spent");
32453242
Err(())
32463243
} else { ret }

lightning/src/ln/channel.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::ln::chan_utils;
4545
use crate::ln::onion_utils::HTLCFailReason;
4646
use crate::chain::BestBlock;
4747
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
48-
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID};
48+
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};
4949
use crate::chain::transaction::{OutPoint, TransactionData};
5050
use crate::sign::ecdsa::EcdsaChannelSigner;
5151
use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
@@ -3656,7 +3656,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
36563656
// monitor update to the user, even if we return one).
36573657
// See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
36583658
if !self.channel_state.is_pre_funded_state() {
3659-
self.latest_monitor_update_id = CLOSED_CHANNEL_UPDATE_ID;
3659+
self.latest_monitor_update_id += 1;
36603660
Some((self.get_counterparty_node_id(), funding_txo, self.channel_id(), ChannelMonitorUpdate {
36613661
update_id: self.latest_monitor_update_id,
36623662
counterparty_node_id: Some(self.counterparty_node_id),

0 commit comments

Comments
 (0)