Skip to content

Commit 0fcc34b

Browse files
committed
Regenerate PendingHTLCsForwardable on reload instead of serializing
When we are prepared to forward HTLCs, we generate a PendingHTLCsForwardable event with a time in the future when the user should tell us to forward. This provides some basic batching of forward events, improving privacy slightly. After we generate the event, we expect users to spawn a timer in the background and let us know when it finishes. However, if the user shuts down before the timer fires, the user will restart and have no idea that HTLCs are waiting to be forwarded/received. To fix this, instead of serializing PendingHTLCsForwardable events to disk while they're pending (before the user starts the timer), we simply regenerate them when a ChannelManager is deserialized with HTLCs pending. Fixes #1042
1 parent 24065c8 commit 0fcc34b

File tree

3 files changed

+132
-12
lines changed

3 files changed

+132
-12
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5276,6 +5276,16 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
52765276
None => continue,
52775277
}
52785278
}
5279+
if forward_htlcs_count > 0 {
5280+
// If we have pending HTLCs to forward, assume we either dropped a
5281+
// `PendingHTLCsForwardable` or the user received it but never processed it as they
5282+
// shut down before the timer hit. Either way, set the time_forwardable to a small
5283+
// constant as enough time has likely passed that we should simply handle the forwards
5284+
// now, or at least after the user gets a chance to reconnect to our peers.
5285+
pending_events_read.push(events::Event::PendingHTLCsForwardable {
5286+
time_forwardable: Duration::from_secs(2),
5287+
});
5288+
}
52795289

52805290
let background_event_count: u64 = Readable::read(reader)?;
52815291
let mut pending_background_events_read: Vec<BackgroundEvent> = Vec::with_capacity(cmp::min(background_event_count as usize, MAX_ALLOC_SIZE/mem::size_of::<BackgroundEvent>()));

lightning/src/ln/functional_tests.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9014,6 +9014,125 @@ fn test_tx_confirmed_skipping_blocks_immediate_broadcast() {
90149014
do_test_tx_confirmed_skipping_blocks_immediate_broadcast(true);
90159015
}
90169016

9017+
#[test]
9018+
fn test_forwardable_regen() {
9019+
// Tests that if we reload a ChannelManager while forwards are pending we will regenerate the
9020+
// PendingHTLCsForwardable event automatically, ensuring we don't forget to forward/receive
9021+
// HTLCs.
9022+
// We test it for both payment receipt and payment forwarding.
9023+
9024+
let chanmon_cfgs = create_chanmon_cfgs(3);
9025+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
9026+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
9027+
let persister: test_utils::TestPersister;
9028+
let new_chain_monitor: test_utils::TestChainMonitor;
9029+
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
9030+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
9031+
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
9032+
create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
9033+
9034+
// First send a payment to nodes[1]
9035+
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
9036+
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
9037+
check_added_monitors!(nodes[0], 1);
9038+
9039+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9040+
assert_eq!(events.len(), 1);
9041+
let payment_event = SendEvent::from_event(events.pop().unwrap());
9042+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9043+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9044+
9045+
expect_pending_htlcs_forwardable_ignore!(nodes[1]);
9046+
9047+
// Next send a payment which is forwarded by nodes[1]
9048+
let (route_2, payment_hash_2, payment_preimage_2, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[2], 200_000);
9049+
nodes[0].node.send_payment(&route_2, payment_hash_2, &Some(payment_secret_2)).unwrap();
9050+
check_added_monitors!(nodes[0], 1);
9051+
9052+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9053+
assert_eq!(events.len(), 1);
9054+
let payment_event = SendEvent::from_event(events.pop().unwrap());
9055+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9056+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9057+
9058+
// There is already a PendingHTLCsForwardable event "pending" so another one will not be
9059+
// generated
9060+
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
9061+
9062+
// Now restart nodes[1] and make sure it regenerates a single PendingHTLCsForwardable
9063+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
9064+
nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
9065+
9066+
let nodes_1_serialized = nodes[1].node.encode();
9067+
let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new());
9068+
let mut chan_1_monitor_serialized = test_utils::TestVecWriter(Vec::new());
9069+
{
9070+
let monitors = nodes[1].chain_monitor.chain_monitor.monitors.read().unwrap();
9071+
let mut monitor_iter = monitors.iter();
9072+
monitor_iter.next().unwrap().1.write(&mut chan_0_monitor_serialized).unwrap();
9073+
monitor_iter.next().unwrap().1.write(&mut chan_1_monitor_serialized).unwrap();
9074+
}
9075+
9076+
persister = test_utils::TestPersister::new();
9077+
let keys_manager = &chanmon_cfgs[1].keys_manager;
9078+
new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[1].chain_source), nodes[1].tx_broadcaster.clone(), nodes[1].logger, node_cfgs[1].fee_estimator, &persister, keys_manager);
9079+
nodes[1].chain_monitor = &new_chain_monitor;
9080+
9081+
let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..];
9082+
let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(
9083+
&mut chan_0_monitor_read, keys_manager).unwrap();
9084+
assert!(chan_0_monitor_read.is_empty());
9085+
let mut chan_1_monitor_read = &chan_1_monitor_serialized.0[..];
9086+
let (_, mut chan_1_monitor) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(
9087+
&mut chan_1_monitor_read, keys_manager).unwrap();
9088+
assert!(chan_1_monitor_read.is_empty());
9089+
9090+
let mut nodes_1_read = &nodes_1_serialized[..];
9091+
let (_, nodes_1_deserialized_tmp) = {
9092+
let mut channel_monitors = HashMap::new();
9093+
channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor);
9094+
channel_monitors.insert(chan_1_monitor.get_funding_txo().0, &mut chan_1_monitor);
9095+
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_1_read, ChannelManagerReadArgs {
9096+
default_config: UserConfig::default(),
9097+
keys_manager,
9098+
fee_estimator: node_cfgs[1].fee_estimator,
9099+
chain_monitor: nodes[1].chain_monitor,
9100+
tx_broadcaster: nodes[1].tx_broadcaster.clone(),
9101+
logger: nodes[1].logger,
9102+
channel_monitors,
9103+
}).unwrap()
9104+
};
9105+
nodes_1_deserialized = nodes_1_deserialized_tmp;
9106+
assert!(nodes_1_read.is_empty());
9107+
9108+
assert!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
9109+
assert!(nodes[1].chain_monitor.watch_channel(chan_1_monitor.get_funding_txo().0, chan_1_monitor).is_ok());
9110+
nodes[1].node = &nodes_1_deserialized;
9111+
check_added_monitors!(nodes[1], 2);
9112+
9113+
reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
9114+
// Note that nodes[1] and nodes[2] resend their funding_locked here since they haven't updated
9115+
// the commitment state.
9116+
reconnect_nodes(&nodes[1], &nodes[2], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
9117+
9118+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
9119+
9120+
expect_pending_htlcs_forwardable!(nodes[1]);
9121+
expect_payment_received!(nodes[1], payment_hash, payment_secret, 100_000);
9122+
check_added_monitors!(nodes[1], 1);
9123+
9124+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
9125+
assert_eq!(events.len(), 1);
9126+
let payment_event = SendEvent::from_event(events.pop().unwrap());
9127+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
9128+
commitment_signed_dance!(nodes[2], nodes[1], payment_event.commitment_msg, false);
9129+
expect_pending_htlcs_forwardable!(nodes[2]);
9130+
expect_payment_received!(nodes[2], payment_hash_2, payment_secret_2, 200_000);
9131+
9132+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
9133+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage_2);
9134+
}
9135+
90179136
#[test]
90189137
fn test_keysend_payments_to_public_node() {
90199138
let chanmon_cfgs = create_chanmon_cfgs(2);

lightning/src/util/events.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,8 @@ impl Writeable for Event {
240240
},
241241
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
242242
4u8.write(writer)?;
243-
write_tlv_fields!(writer, {});
244-
// We don't write the time_fordwardable out at all, as we presume when the user
245-
// deserializes us at least that much time has elapsed.
243+
// Note that we now ignore these on the read end as we'll re-generate them in
244+
// ChannelManager, we write them here only for backwards compatibility.
246245
},
247246
&Event::SpendableOutputs { ref outputs } => {
248247
5u8.write(writer)?;
@@ -336,15 +335,7 @@ impl MaybeReadable for Event {
336335
};
337336
f()
338337
},
339-
4u8 => {
340-
let f = || {
341-
read_tlv_fields!(reader, {});
342-
Ok(Some(Event::PendingHTLCsForwardable {
343-
time_forwardable: Duration::from_secs(0)
344-
}))
345-
};
346-
f()
347-
},
338+
4u8 => Ok(None),
348339
5u8 => {
349340
let f = || {
350341
let mut outputs = VecReadWrapper(Vec::new());

0 commit comments

Comments
 (0)