Skip to content

Commit 68c4b31

Browse files
committed
Add tests for peer reconnection
This intersperses peer reconnection in the middle of a payment flow with an asynchronous signer to verify that things function correctly.
1 parent 2c0bcec commit 68c4b31

File tree

4 files changed

+181
-43
lines changed

4 files changed

+181
-43
lines changed

lightning/src/ln/async_signer_tests.rs

Lines changed: 164 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use bitcoin::secp256k1::PublicKey;
1414
use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider};
1515
use crate::ln::ChannelId;
1616
use crate::ln::functional_test_utils::*;
17+
use crate::ln::msgs;
1718
use crate::ln::msgs::ChannelMessageHandler;
18-
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
19+
use crate::ln::channelmanager::{PaymentId, RAACommitmentOrder, RecipientOnionFields};
1920
use crate::util::test_channel_signer::ops;
2021

2122
const OPS: u32 = ops::GET_PER_COMMITMENT_POINT | ops::RELEASE_COMMITMENT_SECRET | ops::SIGN_COUNTERPARTY_COMMITMENT;
@@ -292,14 +293,19 @@ fn test_funding_signed_0conf() {
292293
/// Disables the signer for the specified channel and then runs `do_fn`, then re-enables the signer
293294
/// and calls `signer_unblocked`.
294295
#[cfg(test)]
295-
pub fn with_async_signer<'a, DoFn>(node: &Node, peer_id: &PublicKey, channel_id: &ChannelId, masks: &Vec<u32>, do_fn: &'a DoFn) where DoFn: Fn() {
296+
pub fn with_async_signer<'a, DoFn, T>(node: &Node, peer_id: &PublicKey, channel_id: &ChannelId, masks: &Vec<u32>, do_fn: &'a DoFn) -> T
297+
where DoFn: Fn() -> T
298+
{
296299
let mask = masks.iter().fold(0, |acc, m| (acc | m));
300+
eprintln!("disabling {}", ops::string_from(mask));
297301
node.set_channel_signer_ops_available(peer_id, channel_id, mask, false);
298-
do_fn();
302+
let res = do_fn();
299303
for mask in masks {
304+
eprintln!("enabling {} and calling signer_unblocked", ops::string_from(*mask));
300305
node.set_channel_signer_ops_available(peer_id, channel_id, *mask, true);
301306
node.node.signer_unblocked(Some((*peer_id, *channel_id)));
302307
}
308+
res
303309
}
304310

305311
#[cfg(test)]
@@ -493,58 +499,175 @@ fn test_payment_sgr() {
493499
do_test_payment(&vec![ops::SIGN_COUNTERPARTY_COMMITMENT, ops::GET_PER_COMMITMENT_POINT, ops::RELEASE_COMMITMENT_SECRET]);
494500
}
495501

496-
#[test]
497-
fn test_peer_disconnect() {
502+
#[cfg(test)]
503+
fn do_test_peer_reconnect(masks: &Vec<u32>) {
498504
let chanmon_cfgs = create_chanmon_cfgs(2);
499505
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
500506
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
501507
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
502-
create_announced_chan_between_nodes(&nodes, 0, 1);
503-
504-
let chan_id = {
505-
let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
506-
let chan_lock = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
507-
let chan_ids = chan_lock.channel_by_id.keys().collect::<Vec<_>>();
508-
let n = chan_ids.len();
509-
assert_eq!(n, 1, "expected one channel, not {}", n);
510-
*chan_ids[0]
511-
};
508+
let (_up1, _up2, channel_id, _tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
512509

513510
// Send a payment.
514-
let src = &nodes[0];
515-
let dst = &nodes[1];
516-
let (route, our_payment_hash, _our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(src, dst, 8000000);
517-
src.node.send_payment_with_route(&route, our_payment_hash,
518-
RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0)).unwrap();
519-
check_added_monitors!(src, 1);
511+
let alice = &nodes[0];
512+
let bob = &nodes[1];
513+
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(alice, bob, 8_000_000);
514+
515+
with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
516+
alice.node.send_payment_with_route(&route, payment_hash,
517+
RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
518+
check_added_monitors!(alice, 1);
519+
let events = alice.node.get_and_clear_pending_msg_events();
520+
assert_eq!(events.len(), 0, "expected 0 events, got {}", events.len());
521+
522+
alice.node.peer_disconnected(&bob.node.get_our_node_id());
523+
bob.node.peer_disconnected(&alice.node.get_our_node_id());
524+
});
525+
526+
with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
527+
let mut reconnect_args = ReconnectArgs::new(alice, bob);
528+
reconnect_args.send_channel_ready = (true, true); // ...since this will be state 1.
529+
reconnect_nodes(reconnect_args);
530+
});
520531

521-
// Pass the payment along the route.
522532
let payment_event = {
523-
let mut events = src.node.get_and_clear_pending_msg_events();
533+
let mut events = alice.node.get_and_clear_pending_msg_events();
524534
assert_eq!(events.len(), 1);
525535
SendEvent::from_event(events.remove(0))
526536
};
527-
assert_eq!(payment_event.node_id, dst.node.get_our_node_id());
537+
assert_eq!(payment_event.node_id, bob.node.get_our_node_id());
528538
assert_eq!(payment_event.msgs.len(), 1);
529539

530-
dst.node.handle_update_add_htlc(&src.node.get_our_node_id(), &payment_event.msgs[0]);
540+
// alice --[update_add_htlc]--> bob
541+
// alice --[commitment_signed]--> bob
542+
with_async_signer(&bob, &alice.node.get_our_node_id(), &channel_id, masks, &|| {
543+
bob.node.handle_update_add_htlc(&alice.node.get_our_node_id(), &payment_event.msgs[0]);
544+
bob.node.handle_commitment_signed(&alice.node.get_our_node_id(), &payment_event.commitment_msg);
545+
check_added_monitors(bob, 1);
531546

532-
// Mark dst's signer as unavailable and handle src's commitment_signed. If dst's signer is
533-
// offline, it oughtn't respond with any updates.
534-
dst.set_channel_signer_ops_available(&src.node.get_our_node_id(), &chan_id, OPS, false);
535-
dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
536-
check_added_monitors(dst, 1);
547+
alice.node.peer_disconnected(&bob.node.get_our_node_id());
548+
bob.node.peer_disconnected(&alice.node.get_our_node_id());
549+
});
537550

538-
// Now disconnect and reconnect the peers.
539-
src.node.peer_disconnected(&dst.node.get_our_node_id());
540-
dst.node.peer_disconnected(&src.node.get_our_node_id());
541-
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
542-
reconnect_args.send_channel_ready = (false, false);
543-
reconnect_args.pending_raa = (false, false);
544-
reconnect_nodes(reconnect_args);
551+
let (alice_reestablish, bob_reestablish) = with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
552+
alice.node.peer_connected(&bob.node.get_our_node_id(), &msgs::Init {
553+
features: bob.node.init_features(), networks: None, remote_network_address: None
554+
}, true).expect("peer_connected failed for alice");
555+
let alice_msgs = get_chan_reestablish_msgs!(alice, bob);
556+
assert_eq!(alice_msgs.len(), 1, "expected 1 message, got {}", alice_msgs.len());
557+
bob.node.peer_connected(&alice.node.get_our_node_id(), &msgs::Init {
558+
features: alice.node.init_features(), networks: None, remote_network_address: None
559+
}, false).expect("peer_connected failed for bob");
560+
let bob_msgs = get_chan_reestablish_msgs!(bob, alice);
561+
assert_eq!(bob_msgs.len(), 1, "expected 1 message, got {}", bob_msgs.len());
562+
(alice_msgs[0].clone(), bob_msgs[0].clone())
563+
});
545564

546-
// Mark dst's signer as available and retry: we now expect to see dst's commitment signed and RAA.
547-
dst.set_channel_signer_ops_available(&src.node.get_our_node_id(), &chan_id, OPS, true);
548-
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
549-
get_revoke_commit_msgs(dst, &src.node.get_our_node_id());
565+
with_async_signer(&bob, &alice.node.get_our_node_id(), &channel_id, masks, &|| {
566+
bob.node.handle_channel_reestablish(&alice.node.get_our_node_id(), &alice_reestablish);
567+
});
568+
569+
let (raa, cu) = match handle_chan_reestablish_msgs!(bob, alice) {
570+
(None, Some(raa), Some(cu), RAACommitmentOrder::RevokeAndACKFirst) => (raa, cu),
571+
(channel_ready, raa, cu, order) => {
572+
panic!("bob: channel_ready={:?} raa={:?} cu={:?} order={:?}", channel_ready, raa, cu, order);
573+
}
574+
};
575+
576+
with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
577+
alice.node.handle_channel_reestablish(&bob.node.get_our_node_id(), &bob_reestablish);
578+
});
579+
580+
match handle_chan_reestablish_msgs!(alice, bob) {
581+
(None, None, None, _) => (),
582+
(channel_ready, raa, cu, order) => {
583+
panic!("alice: channel_ready={:?} raa={:?} cu={:?} order={:?}", channel_ready, raa, cu, order);
584+
}
585+
};
586+
587+
with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
588+
alice.node.handle_revoke_and_ack(&bob.node.get_our_node_id(), &raa);
589+
check_added_monitors(alice, 1);
590+
});
591+
592+
// Disconnect?
593+
594+
with_async_signer(&alice, &bob.node.get_our_node_id(), &channel_id, masks, &|| {
595+
alice.node.handle_commitment_signed(&bob.node.get_our_node_id(), &cu.commitment_signed);
596+
check_added_monitors(alice, 1);
597+
});
598+
599+
// Disconnect?
600+
601+
let raa = get_event_msg!(alice, MessageSendEvent::SendRevokeAndACK, bob.node.get_our_node_id());
602+
with_async_signer(&bob, &alice.node.get_our_node_id(), &channel_id, masks, &|| {
603+
bob.node.handle_revoke_and_ack(&alice.node.get_our_node_id(), &raa);
604+
check_added_monitors(bob, 1);
605+
});
606+
607+
expect_pending_htlcs_forwardable!(bob);
608+
609+
{
610+
let events = bob.node.get_and_clear_pending_events();
611+
assert_eq!(events.len(), 1, "expected 1 event, got {}", events.len());
612+
match &events[0] {
613+
Event::PaymentClaimable { .. } => (),
614+
ev => panic!("Expected PaymentClaimable, got {:?}", ev),
615+
}
616+
}
617+
618+
with_async_signer(&bob, &alice.node.get_our_node_id(), &channel_id, masks, &|| {
619+
bob.node.claim_funds(payment_preimage);
620+
check_added_monitors(bob, 1);
621+
});
622+
623+
let _cu = {
624+
let events = bob.node.get_and_clear_pending_msg_events();
625+
assert_eq!(events.len(), 1, "expected 1 message, got {}", events.len());
626+
match &events[0] {
627+
MessageSendEvent::UpdateHTLCs { ref updates, .. } => updates.clone(),
628+
ev => panic!("expected UpdateHTLCs, got {:?}", ev),
629+
}
630+
};
631+
632+
{
633+
let events = bob.node.get_and_clear_pending_events();
634+
assert_eq!(events.len(), 1, "expected 1 event, got {}", events.len());
635+
match &events[0] {
636+
Event::PaymentClaimed { .. } => (),
637+
ev => panic!("Expected PaymentClaimed, got {:?}", ev),
638+
}
639+
}
640+
641+
// Blah blah blah... send cu to alice, probably sprinkle some reconnects above.
642+
}
643+
644+
#[test]
645+
fn test_peer_reconnect_grs() {
646+
do_test_peer_reconnect(&vec![ops::GET_PER_COMMITMENT_POINT, ops::RELEASE_COMMITMENT_SECRET, ops::SIGN_COUNTERPARTY_COMMITMENT]);
647+
}
648+
649+
#[test]
650+
fn test_peer_reconnect_gsr() {
651+
do_test_peer_reconnect(&vec![ops::GET_PER_COMMITMENT_POINT, ops::SIGN_COUNTERPARTY_COMMITMENT, ops::RELEASE_COMMITMENT_SECRET]);
652+
}
653+
654+
#[test]
655+
fn test_peer_reconnect_rsg() {
656+
do_test_peer_reconnect(&vec![ops::RELEASE_COMMITMENT_SECRET, ops::SIGN_COUNTERPARTY_COMMITMENT, ops::GET_PER_COMMITMENT_POINT]);
657+
}
658+
659+
#[test]
660+
fn test_peer_reconnect_rgs() {
661+
do_test_peer_reconnect(&vec![ops::RELEASE_COMMITMENT_SECRET, ops::GET_PER_COMMITMENT_POINT, ops::SIGN_COUNTERPARTY_COMMITMENT]);
550662
}
663+
664+
#[test]
665+
fn test_peer_reconnect_srg() {
666+
do_test_peer_reconnect(&vec![ops::SIGN_COUNTERPARTY_COMMITMENT, ops::RELEASE_COMMITMENT_SECRET, ops::GET_PER_COMMITMENT_POINT]);
667+
}
668+
669+
#[test]
670+
fn test_peer_reconnect_sgr() {
671+
do_test_payment(&vec![ops::SIGN_COUNTERPARTY_COMMITMENT, ops::GET_PER_COMMITMENT_POINT, ops::RELEASE_COMMITMENT_SECRET]);
672+
}
673+

lightning/src/ln/channel.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ pub(super) struct MonitorRestoreUpdates {
537537
/// When the signer becomes unblocked, any non-`None` event accumulated here should be sent to the
538538
/// peer by the caller.
539539
#[allow(unused)]
540+
#[derive(Default)]
540541
pub(super) struct SignerResumeUpdates {
541542
/// A `commitment_signed` message, possibly with additional HTLC-related messages (e.g.,
542543
/// `update_add_htlc`) that should be placed in the commitment.
@@ -4102,6 +4103,11 @@ impl<SP: Deref> Channel<SP> where
41024103
self.context.update_holder_per_commitment(logger);
41034104
}
41044105

4106+
if self.context.channel_state & (ChannelState::PeerDisconnected as u32) != 0 {
4107+
log_trace!(logger, "Peer is disconnected; no unblocked messages to send.");
4108+
return SignerResumeUpdates::default()
4109+
}
4110+
41054111
// Make sure that we honor any ordering requirements between the commitment update and revoke-and-ack.
41064112
let (commitment_update, raa) = match &self.context.resend_order {
41074113
RAACommitmentOrder::CommitmentFirst => {
@@ -4461,6 +4467,7 @@ impl<SP: Deref> Channel<SP> where
44614467

44624468
let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number == 1 {
44634469
// We should never have to worry about MonitorUpdateInProgress resending ChannelReady
4470+
log_debug!(logger, "Reconnecting channel at state 1, (re?)sending channel_ready");
44644471
self.get_channel_ready().or_else(|| {
44654472
self.context.signer_pending_channel_ready = true;
44664473
None

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,10 @@ pub(super) const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u64 = 100;
511511
/// be sent in the order they appear in the return value, however sometimes the order needs to be
512512
/// variable at runtime (eg Channel::channel_reestablish needs to re-send messages in the order
513513
/// they were originally sent). In those cases, this enum is also returned.
514-
#[derive(Clone, PartialEq)]
514+
#[derive(Clone, Debug, Default, PartialEq)]
515515
pub(super) enum RAACommitmentOrder {
516516
/// Send the CommitmentUpdate messages first
517+
#[default]
517518
CommitmentFirst,
518519
/// Send the RevokeAndACK message first
519520
RevokeAndACKFirst,

lightning/src/ln/functional_test_utils.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3003,7 +3003,7 @@ macro_rules! get_chan_reestablish_msgs {
30033003
assert_eq!(*node_id, $dst_node.node.get_our_node_id());
30043004
announcements.insert(msg.contents.short_channel_id);
30053005
} else {
3006-
panic!("Unexpected event")
3006+
panic!("Unexpected event re-establishing channel, {:?}", msg)
30073007
}
30083008
}
30093009
assert!(announcements.is_empty());
@@ -3059,6 +3059,13 @@ macro_rules! handle_chan_reestablish_msgs {
30593059
RAACommitmentOrder::CommitmentFirst
30603060
};
30613061

3062+
if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, .. }) = msg_events.get(idx) {
3063+
assert_eq!(*node_id, $dst_node.node.get_our_node_id());
3064+
idx += 1;
3065+
assert!(!had_channel_update);
3066+
had_channel_update = true;
3067+
}
3068+
30623069
if let Some(ev) = msg_events.get(idx) {
30633070
match ev {
30643071
&MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {

0 commit comments

Comments
 (0)