Skip to content

Commit 5885d3f

Browse files
committed
Always release MonitorEvents to ChannelManager after 3 blocks
If we have a `ChannelMonitor` update from an on-chain event which returns a `TemporaryFailure`, we block `MonitorEvent`s from that `ChannelMonitor` until the update is persisted. This prevents duplicate payment send events to the user after payments get reloaded from monitors on restart. However, if the event being avoided isn't going to generate a PaymentSent, but instead result in us claiming an HTLC from an upstream channel (ie the HTLC was forwarded), then the result of a user delaying the event is that we delay getting our money, not a duplicate event. Because user persistence may take an arbitrary amount of time, we need to bound the amount of time we can possibly wait to return events, which we do here by bounding it to 3 blocks. Thanks to Val for catching this in review.
1 parent 8c65801 commit 5885d3f

File tree

1 file changed

+49
-11
lines changed

1 file changed

+49
-11
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bitcoin::hash_types::Txid;
2929
use chain;
3030
use chain::{ChannelMonitorUpdateErr, Filter, WatchedOutput};
3131
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
32-
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs};
32+
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs, LATENCY_GRACE_PERIOD_BLOCKS};
3333
use chain::transaction::{OutPoint, TransactionData};
3434
use chain::keysinterface::Sign;
3535
use util::atomic_counter::AtomicCounter;
@@ -42,7 +42,7 @@ use ln::channelmanager::ChannelDetails;
4242
use prelude::*;
4343
use sync::{RwLock, RwLockReadGuard, Mutex, MutexGuard};
4444
use core::ops::Deref;
45-
use core::sync::atomic::{AtomicBool, Ordering};
45+
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
4646

4747
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
4848
/// A specific update stored in a `MonitorUpdateId`, separated out to make the contents entirely
@@ -165,6 +165,13 @@ struct MonitorHolder<ChannelSigner: Sign> {
165165
/// processed the closure event, we set this to true and return PermanentFailure for any other
166166
/// chain::Watch events.
167167
channel_perm_failed: AtomicBool,
168+
/// The last block height at which which no [`UpdateOrigin::ChainSync`] monitor updates were
169+
/// present in `pending_monitor_updates`.
170+
/// If its been more than [`LATENCY_GRACE_PERIOD_BLOCKS`] since we started waiting on a chain
171+
/// sync event, we let montior events return to `ChannelManager` because we cannot hold them up
172+
/// forever or we'll end up with HTLC preimages waiting to feed back into an upstream channel
173+
/// forever, risking funds loss.
174+
last_chain_persist_height: AtomicUsize,
168175
}
169176

170177
impl<ChannelSigner: Sign> MonitorHolder<ChannelSigner> {
@@ -223,6 +230,8 @@ pub struct ChainMonitor<ChannelSigner: Sign, C: Deref, T: Deref, F: Deref, L: De
223230
/// "User-provided" (ie persistence-completion/-failed) [`MonitorEvent`]s. These came directly
224231
/// from the user and not from a [`ChannelMonitor`].
225232
pending_monitor_events: Mutex<Vec<MonitorEvent>>,
233+
/// The best block height seen, used as a proxy for the passage of time.
234+
highest_chain_height: AtomicUsize,
226235
}
227236

228237
impl<ChannelSigner: Sign, C: Deref, T: Deref, F: Deref, L: Deref, P: Deref> ChainMonitor<ChannelSigner, C, T, F, L, P>
@@ -241,11 +250,16 @@ where C::Target: chain::Filter,
241250
/// calls must not exclude any transactions matching the new outputs nor any in-block
242251
/// descendants of such transactions. It is not necessary to re-fetch the block to obtain
243252
/// updated `txdata`.
244-
fn process_chain_data<FN>(&self, header: &BlockHeader, txdata: &TransactionData, process: FN)
253+
///
254+
/// Calls which represent a new blockchain tip height should set `best_height`.
255+
fn process_chain_data<FN>(&self, header: &BlockHeader, best_height: Option<u32>, txdata: &TransactionData, process: FN)
245256
where
246257
FN: Fn(&ChannelMonitor<ChannelSigner>, &TransactionData) -> Vec<TransactionOutputs>
247258
{
248259
let mut dependent_txdata = Vec::new();
260+
if let Some(height) = best_height {
261+
self.highest_chain_height.store(height as usize, Ordering::Release);
262+
}
249263
{
250264
let monitor_states = self.monitors.write().unwrap();
251265
for (funding_outpoint, monitor_state) in monitor_states.iter() {
@@ -257,6 +271,16 @@ where C::Target: chain::Filter,
257271
contents: UpdateOrigin::ChainSync(self.sync_persistence_id.get_increment()),
258272
};
259273
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
274+
if let Some(height) = best_height {
275+
if !pending_monitor_updates.iter().any(|update_id|
276+
if let UpdateOrigin::ChainSync(_) = update_id.contents { true } else { false })
277+
{
278+
// If there are not ChainSync persists awaiting completion, go ahead and
279+
// set last_chain_persist_height here - we wouldn't want the first
280+
// TemporaryFailure to always immediately be considered "overly delayed".
281+
monitor_state.last_chain_persist_height.store(height as usize, Ordering::Release);
282+
}
283+
}
260284

261285
log_trace!(self.logger, "Syncing Channel Monitor for channel {}", log_funding_info!(monitor));
262286
match self.persister.update_persisted_channel(*funding_outpoint, &None, monitor, update_id) {
@@ -301,7 +325,7 @@ where C::Target: chain::Filter,
301325
dependent_txdata.sort_unstable_by_key(|(index, _tx)| *index);
302326
dependent_txdata.dedup_by_key(|(index, _tx)| *index);
303327
let txdata: Vec<_> = dependent_txdata.iter().map(|(index, tx)| (*index, tx)).collect();
304-
self.process_chain_data(header, &txdata, process);
328+
self.process_chain_data(header, None, &txdata, process); // We skip the best height the second go-around
305329
}
306330
}
307331

@@ -322,6 +346,7 @@ where C::Target: chain::Filter,
322346
fee_estimator: feeest,
323347
persister,
324348
pending_monitor_events: Mutex::new(Vec::new()),
349+
highest_chain_height: AtomicUsize::new(0),
325350
}
326351
}
327352

@@ -425,9 +450,13 @@ where C::Target: chain::Filter,
425450
});
426451
},
427452
MonitorUpdateId { contents: UpdateOrigin::ChainSync(_) } => {
428-
// We've already done everything we need to, the next time
429-
// release_pending_monitor_events is called, any events for this ChannelMonitor
430-
// will be returned if there's no more SyncPersistId events left.
453+
if !pending_monitor_updates.iter().any(|update_id|
454+
if let UpdateOrigin::ChainSync(_) = update_id.contents { true } else { false })
455+
{
456+
monitor_data.last_chain_persist_height.store(self.highest_chain_height.load(Ordering::Acquire), Ordering::Release);
457+
// The next time release_pending_monitor_events is called, any events for this
458+
// ChannelMonitor will be returned.
459+
}
431460
},
432461
}
433462
Ok(())
@@ -467,7 +496,7 @@ where
467496
let header = &block.header;
468497
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
469498
log_debug!(self.logger, "New best block {} at height {} provided via block_connected", header.block_hash(), height);
470-
self.process_chain_data(header, &txdata, |monitor, txdata| {
499+
self.process_chain_data(header, Some(height), &txdata, |monitor, txdata| {
471500
monitor.block_connected(
472501
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
473502
});
@@ -494,7 +523,7 @@ where
494523
{
495524
fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
496525
log_debug!(self.logger, "{} provided transactions confirmed at height {} in block {}", txdata.len(), height, header.block_hash());
497-
self.process_chain_data(header, txdata, |monitor, txdata| {
526+
self.process_chain_data(header, None, txdata, |monitor, txdata| {
498527
monitor.transactions_confirmed(
499528
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
500529
});
@@ -510,7 +539,7 @@ where
510539

511540
fn best_block_updated(&self, header: &BlockHeader, height: u32) {
512541
log_debug!(self.logger, "New best block {} at height {} provided via best_block_updated", header.block_hash(), height);
513-
self.process_chain_data(header, &[], |monitor, txdata| {
542+
self.process_chain_data(header, Some(height), &[], |monitor, txdata| {
514543
// While in practice there shouldn't be any recursive calls when given empty txdata,
515544
// it's still possible if a chain::Filter implementation returns a transaction.
516545
debug_assert!(txdata.is_empty());
@@ -577,6 +606,7 @@ where C::Target: chain::Filter,
577606
monitor,
578607
pending_monitor_updates: Mutex::new(pending_monitor_updates),
579608
channel_perm_failed: AtomicBool::new(false),
609+
last_chain_persist_height: AtomicUsize::new(0),
580610
});
581611
persist_res
582612
}
@@ -633,7 +663,10 @@ where C::Target: chain::Filter,
633663
let mut pending_monitor_events = self.pending_monitor_events.lock().unwrap().split_off(0);
634664
for monitor_state in self.monitors.read().unwrap().values() {
635665
let is_pending_monitor_update = monitor_state.has_pending_chainsync_updates(&monitor_state.pending_monitor_updates.lock().unwrap());
636-
if is_pending_monitor_update {
666+
if is_pending_monitor_update &&
667+
monitor_state.last_chain_persist_height.load(Ordering::Acquire) + LATENCY_GRACE_PERIOD_BLOCKS as usize
668+
> self.highest_chain_height.load(Ordering::Acquire)
669+
{
637670
log_info!(self.logger, "A Channel Monitor sync is still in progress, refusing to provide monitor events!");
638671
} else {
639672
if monitor_state.channel_perm_failed.load(Ordering::Acquire) {
@@ -647,6 +680,11 @@ where C::Target: chain::Filter,
647680
// updated.
648681
log_info!(self.logger, "A Channel Monitor sync returned PermanentFailure. Returning monitor events but duplicate events may appear after reload!");
649682
}
683+
if is_pending_monitor_update {
684+
log_error!(self.logger, "A ChannelMonitor sync took longer than {} blocks to complete.", LATENCY_GRACE_PERIOD_BLOCKS);
685+
log_error!(self.logger, " To avoid funds-loss, we are allowing monitor updates to be released.");
686+
log_error!(self.logger, " This may cause duplicate payment events to be generated.");
687+
}
650688
pending_monitor_events.append(&mut monitor_state.monitor.get_and_clear_pending_monitor_events());
651689
}
652690
}

0 commit comments

Comments
 (0)