Skip to content

Commit 56f979b

Browse files
committed
Track actions to execute after a ChannelMonitor is updated
When a `ChannelMonitor` update completes, we may need to take some further action, such as exposing an `Event` to the user initiating another `ChannelMonitor` update, etc. This commit adds the basic structure to track such actions and serialize them as required. Note that while this does introduce a new map which is written as an even value which users cannot opt out of, the map is only filled in when users use the asynchronous `ChannelMonitor` updates. As these are still considered beta, breaking downgrades for such users is considered acceptable here.
1 parent 8aa518f commit 56f979b

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, Maybe
6565
use crate::util::logger::{Level, Logger};
6666
use crate::util::errors::APIError;
6767

68+
use alloc::collections::BTreeMap;
69+
6870
use crate::io;
6971
use crate::prelude::*;
7072
use core::{cmp, mem};
@@ -474,6 +476,11 @@ pub(crate) enum MonitorUpdateCompletionAction {
474476
EmitEvent { event: events::Event },
475477
}
476478

479+
impl_writeable_tlv_based_enum_upgradable!(MonitorUpdateCompletionAction,
480+
(0, PaymentClaimed) => { (0, payment_hash, required) },
481+
(2, EmitEvent) => { (0, event, ignorable) },
482+
);
483+
477484
/// State we hold per-peer.
478485
pub(super) struct PeerState<Signer: ChannelSigner> {
479486
/// `temporary_channel_id` or `channel_id` -> `channel`.
@@ -487,6 +494,21 @@ pub(super) struct PeerState<Signer: ChannelSigner> {
487494
/// Messages to send to the peer - pushed to in the same lock that they are generated in (except
488495
/// for broadcast messages, where ordering isn't as strict).
489496
pub(super) pending_msg_events: Vec<MessageSendEvent>,
497+
/// Map from a specific channel to some action(s) that should be taken when all pending
498+
/// [`ChannelMonitorUpdate`]s for the channel complete updating.
499+
///
500+
/// Note that because we generally only have one entry here a HashMap is pretty overkill. A
501+
/// BTreeMap currently stores more than ten elements per leaf node, so even up to a few
502+
/// channels with a peer this will just be one allocation and will amount to a linear list of
503+
/// channels to walk, avoiding the whole hashing rigmarole.
504+
///
505+
/// Note that the channel may no longer exist. For example, if a channel was closed but we
506+
/// later needed to claim an HTLC which is pending on-chain, we may generate a monitor update
507+
/// for a missing channel. While a malicious peer could construct a second channel with the
508+
/// same `temporary_channel_id` (or final `channel_id` in the case of 0conf channels or prior
509+
/// to funding appearing on-chain), the downstream `ChannelMonitor` set is required to ensure
510+
/// duplicates do not occur, so such channels should fail without a monitor update completing.
511+
monitor_update_blocked_actions: BTreeMap<[u8; 32], Vec<MonitorUpdateCompletionAction>>,
490512
/// The peer is currently connected (i.e. we've seen a
491513
/// [`ChannelMessageHandler::peer_connected`] and no corresponding
492514
/// [`ChannelMessageHandler::peer_disconnected`].
@@ -501,7 +523,7 @@ impl <Signer: ChannelSigner> PeerState<Signer> {
501523
if require_disconnected && self.is_connected {
502524
return false
503525
}
504-
self.channel_by_id.len() == 0
526+
self.channel_by_id.is_empty() && self.monitor_update_blocked_actions.is_empty()
505527
}
506528
}
507529

@@ -6319,6 +6341,7 @@ where
63196341
channel_by_id: HashMap::new(),
63206342
latest_features: init_msg.features.clone(),
63216343
pending_msg_events: Vec::new(),
6344+
monitor_update_blocked_actions: BTreeMap::new(),
63226345
is_connected: true,
63236346
}));
63246347
},
@@ -6946,17 +6969,26 @@ where
69466969
htlc_purposes.push(purpose);
69476970
}
69486971

6972+
let mut monitor_update_blocked_actions_per_peer = None;
6973+
let mut peer_states = Vec::new();
6974+
for (_, peer_state_mutex) in per_peer_state.iter() {
6975+
peer_states.push(peer_state_mutex.lock().unwrap());
6976+
}
6977+
69496978
(serializable_peer_count).write(writer)?;
6950-
for (peer_pubkey, peer_state_mutex) in per_peer_state.iter() {
6951-
let peer_state_lock = peer_state_mutex.lock().unwrap();
6952-
let peer_state = &*peer_state_lock;
6979+
for ((peer_pubkey, _), peer_state) in per_peer_state.iter().zip(peer_states.iter()) {
69536980
// Peers which we have no channels to should be dropped once disconnected. As we
69546981
// disconnect all peers when shutting down and serializing the ChannelManager, we
69556982
// consider all peers as disconnected here. There's therefore no need write peers with
69566983
// no channels.
69576984
if !peer_state.ok_to_remove(false) {
69586985
peer_pubkey.write(writer)?;
69596986
peer_state.latest_features.write(writer)?;
6987+
if !peer_state.monitor_update_blocked_actions.is_empty() {
6988+
monitor_update_blocked_actions_per_peer
6989+
.get_or_insert_with(Vec::new)
6990+
.push((*peer_pubkey, &peer_state.monitor_update_blocked_actions));
6991+
}
69606992
}
69616993
}
69626994

@@ -7044,6 +7076,7 @@ where
70447076
(3, pending_outbound_payments, required),
70457077
(4, pending_claiming_payments, option),
70467078
(5, self.our_network_pubkey, required),
7079+
(6, monitor_update_blocked_actions_per_peer, option),
70477080
(7, self.fake_scid_rand_bytes, required),
70487081
(9, htlc_purposes, vec_type),
70497082
(11, self.probing_cookie_secret, required),
@@ -7356,6 +7389,7 @@ where
73567389
channel_by_id: peer_channels.remove(&peer_pubkey).unwrap_or(HashMap::new()),
73577390
latest_features: Readable::read(reader)?,
73587391
pending_msg_events: Vec::new(),
7392+
monitor_update_blocked_actions: BTreeMap::new(),
73597393
is_connected: false,
73607394
};
73617395
per_peer_state.insert(peer_pubkey, Mutex::new(peer_state));
@@ -7412,12 +7446,14 @@ where
74127446
let mut probing_cookie_secret: Option<[u8; 32]> = None;
74137447
let mut claimable_htlc_purposes = None;
74147448
let mut pending_claiming_payments = Some(HashMap::new());
7449+
let mut monitor_update_blocked_actions_per_peer = Some(Vec::new());
74157450
read_tlv_fields!(reader, {
74167451
(1, pending_outbound_payments_no_retry, option),
74177452
(2, pending_intercepted_htlcs, option),
74187453
(3, pending_outbound_payments, option),
74197454
(4, pending_claiming_payments, option),
74207455
(5, received_network_pubkey, option),
7456+
(6, monitor_update_blocked_actions_per_peer, option),
74217457
(7, fake_scid_rand_bytes, option),
74227458
(9, claimable_htlc_purposes, vec_type),
74237459
(11, probing_cookie_secret, option),
@@ -7683,6 +7719,15 @@ where
76837719
}
76847720
}
76857721

7722+
for (node_id, monitor_update_blocked_actions) in monitor_update_blocked_actions_per_peer.unwrap() {
7723+
if let Some(peer_state) = per_peer_state.get_mut(&node_id) {
7724+
peer_state.lock().unwrap().monitor_update_blocked_actions = monitor_update_blocked_actions;
7725+
} else {
7726+
log_error!(args.logger, "Got blocked actions without a per-peer-state for {}", node_id);
7727+
return Err(DecodeError::InvalidValue);
7728+
}
7729+
}
7730+
76867731
let channel_manager = ChannelManager {
76877732
genesis_hash,
76887733
fee_estimator: bounded_fee_estimator,

lightning/src/util/ser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ impl Readable for Vec<u8> {
770770
}
771771

772772
impl_for_vec!(ecdsa::Signature);
773+
impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
773774
impl_for_vec!((A, B), A, B);
774775

775776
impl Writeable for Script {

0 commit comments

Comments
 (0)