Skip to content

Commit f534ce2

Browse files
authored
Merge pull request #2621 from G8XSU/dont-persist-erroneous-update
Persist entire monitor if there is an error while applying monitor_update
2 parents e0fe325 + 976acd8 commit f534ce2

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

lightning/src/chain/chainmonitor.rs

+38-20
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,35 @@ use core::ops::Deref;
4747
use core::sync::atomic::{AtomicUsize, Ordering};
4848
use bitcoin::secp256k1::PublicKey;
4949

50-
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
51-
/// A specific update's ID stored in a `MonitorUpdateId`, separated out to make the contents
52-
/// entirely opaque.
53-
enum UpdateOrigin {
54-
/// An update that was generated by the `ChannelManager` (via our `chain::Watch`
55-
/// implementation). This corresponds to an actual [`ChannelMonitorUpdate::update_id`] field
56-
/// and [`ChannelMonitor::get_latest_update_id`].
57-
OffChain(u64),
58-
/// An update that was generated during blockchain processing. The ID here is specific to the
59-
/// generating [`ChainMonitor`] and does *not* correspond to any on-disk IDs.
60-
ChainSync(u64),
50+
mod update_origin {
51+
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
52+
/// A specific update's ID stored in a `MonitorUpdateId`, separated out to make the contents
53+
/// entirely opaque.
54+
pub(crate) enum UpdateOrigin {
55+
/// An update that was generated by the `ChannelManager` (via our [`crate::chain::Watch`]
56+
/// implementation). This corresponds to an actual [ChannelMonitorUpdate::update_id] field
57+
/// and [ChannelMonitor::get_latest_update_id].
58+
///
59+
/// [ChannelMonitor::get_latest_update_id]: crate::chain::channelmonitor::ChannelMonitor::get_latest_update_id
60+
/// [ChannelMonitorUpdate::update_id]: crate::chain::channelmonitor::ChannelMonitorUpdate::update_id
61+
OffChain(u64),
62+
/// An update that was generated during blockchain processing. The ID here is specific to the
63+
/// generating [ChannelMonitor] and does *not* correspond to any on-disk IDs.
64+
///
65+
/// [ChannelMonitor]: crate::chain::channelmonitor::ChannelMonitor
66+
ChainSync(u64),
67+
}
6168
}
6269

70+
#[cfg(any(feature = "_test_utils", test))]
71+
pub(crate) use update_origin::UpdateOrigin;
72+
#[cfg(not(any(feature = "_test_utils", test)))]
73+
use update_origin::UpdateOrigin;
74+
6375
/// An opaque identifier describing a specific [`Persist`] method call.
6476
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
6577
pub struct MonitorUpdateId {
66-
contents: UpdateOrigin,
78+
pub(crate) contents: UpdateOrigin,
6779
}
6880

6981
impl MonitorUpdateId {
@@ -155,8 +167,8 @@ pub trait Persist<ChannelSigner: WriteableEcdsaChannelSigner> {
155167
/// updated monitor itself to disk/backups. See the [`Persist`] trait documentation for more
156168
/// details.
157169
///
158-
/// During blockchain synchronization operations, this may be called with no
159-
/// [`ChannelMonitorUpdate`], in which case the full [`ChannelMonitor`] needs to be persisted.
170+
/// During blockchain synchronization operations, and in some rare cases, this may be called with
171+
/// no [`ChannelMonitorUpdate`], in which case the full [`ChannelMonitor`] needs to be persisted.
160172
/// Note that after the full [`ChannelMonitor`] is persisted any previous
161173
/// [`ChannelMonitorUpdate`]s which were persisted should be discarded - they can no longer be
162174
/// applied to the persisted [`ChannelMonitor`] as they were already applied.
@@ -756,14 +768,20 @@ where C::Target: chain::Filter,
756768
let monitor = &monitor_state.monitor;
757769
log_trace!(self.logger, "Updating ChannelMonitor for channel {}", log_funding_info!(monitor));
758770
let update_res = monitor.update_monitor(update, &self.broadcaster, &*self.fee_estimator, &self.logger);
759-
if update_res.is_err() {
760-
log_error!(self.logger, "Failed to update ChannelMonitor for channel {}.", log_funding_info!(monitor));
761-
}
762-
// Even if updating the monitor returns an error, the monitor's state will
763-
// still be changed. So, persist the updated monitor despite the error.
771+
764772
let update_id = MonitorUpdateId::from_monitor_update(update);
765773
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
766-
let persist_res = self.persister.update_persisted_channel(funding_txo, Some(update), monitor, update_id);
774+
let persist_res = if update_res.is_err() {
775+
// Even if updating the monitor returns an error, the monitor's state will
776+
// still be changed. Therefore, we should persist the updated monitor despite the error.
777+
// We don't want to persist a `monitor_update` which results in a failure to apply later
778+
// while reading `channel_monitor` with updates from storage. Instead, we should persist
779+
// the entire `channel_monitor` here.
780+
log_warn!(self.logger, "Failed to update ChannelMonitor for channel {}. Going ahead and persisting the entire ChannelMonitor", log_funding_info!(monitor));
781+
self.persister.update_persisted_channel(funding_txo, None, monitor, update_id)
782+
} else {
783+
self.persister.update_persisted_channel(funding_txo, Some(update), monitor, update_id)
784+
};
767785
match persist_res {
768786
ChannelMonitorUpdateStatus::InProgress => {
769787
pending_monitor_updates.push(update_id);

lightning/src/util/test_utils.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::chain::chaininterface;
1313
use crate::chain::chaininterface::ConfirmationTarget;
1414
use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW;
1515
use crate::chain::chainmonitor;
16-
use crate::chain::chainmonitor::MonitorUpdateId;
16+
use crate::chain::chainmonitor::{MonitorUpdateId, UpdateOrigin};
1717
use crate::chain::channelmonitor;
1818
use crate::chain::channelmonitor::MonitorEvent;
1919
use crate::chain::transaction::OutPoint;
@@ -428,7 +428,8 @@ impl<Signer: sign::WriteableEcdsaChannelSigner> chainmonitor::Persist<Signer> fo
428428
if let Some(update_ret) = self.update_rets.lock().unwrap().pop_front() {
429429
ret = update_ret;
430430
}
431-
if update.is_none() {
431+
let is_chain_sync = if let UpdateOrigin::ChainSync(_) = update_id.contents { true } else { false };
432+
if is_chain_sync {
432433
self.chain_sync_monitor_persistences.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);
433434
} else {
434435
self.offchain_monitor_updates.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);

0 commit comments

Comments
 (0)