diff --git a/lightning/src/ln/async_signer_tests.rs b/lightning/src/ln/async_signer_tests.rs index 459c27863d2..c90db503aea 100644 --- a/lightning/src/ln/async_signer_tests.rs +++ b/lightning/src/ln/async_signer_tests.rs @@ -287,9 +287,125 @@ fn test_async_commitment_signature_for_funding_signed_0conf() { assert_eq!(nodes[1].node.list_usable_channels().len(), 1); } +#[derive(PartialEq)] +enum UnblockSignerAcrossDisconnectCase { + AtEnd, + BeforeMonitorRestored, + BeforeReestablish, +} + +#[test] +fn test_async_raa_peer_disconnect() { + do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::AtEnd); + do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored); + do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeReestablish); +} + +fn do_test_async_raa_peer_disconnect(test_case: UnblockSignerAcrossDisconnectCase) { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (_, _, chan_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1); + + // Send a payment. + let src = &nodes[0]; + let dst = &nodes[1]; + let (route, our_payment_hash, _our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(src, dst, 8000000); + src.node.send_payment_with_route(&route, our_payment_hash, + RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0)).unwrap(); + check_added_monitors!(src, 1); + + // Pass the payment along the route. + let payment_event = { + let mut events = src.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + SendEvent::from_event(events.remove(0)) + }; + assert_eq!(payment_event.node_id, dst.node.get_our_node_id()); + assert_eq!(payment_event.msgs.len(), 1); + + dst.node.handle_update_add_htlc(&src.node.get_our_node_id(), &payment_event.msgs[0]); + + if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored { + // Fail to persist the monitor update when handling the commitment_signed. + chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress); + } + + // Mark dst's signer as unavailable and handle src's commitment_signed: while dst won't yet have a + // `commitment_signed` of its own to offer, it should publish a `revoke_and_ack`. + dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint); + dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg); + check_added_monitors(dst, 1); + + let events = dst.node.get_and_clear_pending_msg_events(); + assert!(events.is_empty(), "expected no message, got {}", events.len()); + + // Now disconnect and reconnect the peers. + src.node.peer_disconnected(&dst.node.get_our_node_id()); + dst.node.peer_disconnected(&src.node.get_our_node_id()); + + // do reestablish stuff + src.node.peer_connected(&dst.node.get_our_node_id(), &msgs::Init { + features: dst.node.init_features(), networks: None, remote_network_address: None + }, true).unwrap(); + let reestablish_1 = get_chan_reestablish_msgs!(src, dst); + assert_eq!(reestablish_1.len(), 1); + dst.node.peer_connected(&src.node.get_our_node_id(), &msgs::Init { + features: src.node.init_features(), networks: None, remote_network_address: None + }, false).unwrap(); + let reestablish_2 = get_chan_reestablish_msgs!(dst, src); + assert_eq!(reestablish_2.len(), 1); + + if test_case == UnblockSignerAcrossDisconnectCase::BeforeReestablish { + // Reenable the signer before the reestablish. + dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint); + } + + dst.node.handle_channel_reestablish(&src.node.get_our_node_id(), &reestablish_1[0]); + + if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored { + dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint); + chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed); + let (outpoint, latest_update, _) = dst.chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id).unwrap().clone(); + dst.chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update); + check_added_monitors!(dst, 0); + } + + // Expect the RAA + let (_, revoke_and_ack, commitment_signed, resend_order) = handle_chan_reestablish_msgs!(dst, src); + if test_case == UnblockSignerAcrossDisconnectCase::AtEnd { + assert!(revoke_and_ack.is_none()); + assert!(commitment_signed.is_none()); + } else { + assert!(revoke_and_ack.is_some()); + assert!(commitment_signed.is_some()); + assert!(resend_order == RAACommitmentOrder::RevokeAndACKFirst); + } + + // Mark dst's signer as available and retry: we now expect to see dst's RAA + CS. + dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint); + dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id))); + + if test_case == UnblockSignerAcrossDisconnectCase::AtEnd { + let (_, revoke_and_ack, commitment_signed, resend_order) = handle_chan_reestablish_msgs!(dst, src); + assert!(revoke_and_ack.is_some()); + assert!(commitment_signed.is_some()); + assert!(resend_order == RAACommitmentOrder::RevokeAndACKFirst); + } else { + // Make sure we don't double send the RAA. + let (_, revoke_and_ack, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src); + assert!(revoke_and_ack.is_none()); + assert!(commitment_signed.is_none()); + } +} + + #[test] fn test_async_commitment_signature_peer_disconnect() { - do_test_async_commitment_signature_peer_disconnect(0); + // This tests that if our signer is blocked and gets unblocked + // after a peer disconnect + channel reestablish, we'll send the right messages. + do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::AtEnd); } #[test] @@ -298,7 +414,7 @@ fn test_async_commitment_signature_peer_disconnect_signer_restored_before_monito // and needed to send a CS, that if our signer becomes available before the monitor // update completes, then we don't send duplicate messages upon calling `signer_unblocked` // after the monitor update completes. - do_test_async_commitment_signature_peer_disconnect(1); + do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored); } #[test] @@ -306,10 +422,10 @@ fn test_async_commitment_signature_peer_disconnect_signer_restored_before_reesta // This tests that if we tried to send a commitment_signed, but our signer was blocked, // if we disconnect, reconnect, the signer becomes available, then handle channel_reestablish, // that we don't send duplicate messages upon calling `signer_unblocked`. - do_test_async_commitment_signature_peer_disconnect(2); + do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeReestablish); } -fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { +fn do_test_async_commitment_signature_peer_disconnect(test_case: UnblockSignerAcrossDisconnectCase) { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); @@ -335,7 +451,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { dst.node.handle_update_add_htlc(&src.node.get_our_node_id(), &payment_event.msgs[0]); - if test_case == 1 { + if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored { // Fail to persist the monitor update when handling the commitment_signed. chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress); } @@ -346,7 +462,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg); check_added_monitors(dst, 1); - if test_case != 1 { + if test_case != UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored { get_event_msg!(dst, MessageSendEvent::SendRevokeAndACK, src.node.get_our_node_id()); } @@ -366,14 +482,14 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { let reestablish_2 = get_chan_reestablish_msgs!(dst, src); assert_eq!(reestablish_2.len(), 1); - if test_case == 2 { + if test_case == UnblockSignerAcrossDisconnectCase::BeforeReestablish { // Reenable the signer before the reestablish. dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment); } dst.node.handle_channel_reestablish(&src.node.get_our_node_id(), &reestablish_1[0]); - if test_case == 1 { + if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored { dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment); chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed); let (outpoint, latest_update, _) = dst.chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id).unwrap().clone(); @@ -384,7 +500,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { // Expect the RAA let (_, revoke_and_ack, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src); assert!(revoke_and_ack.is_some()); - if test_case == 0 { + if test_case == UnblockSignerAcrossDisconnectCase::AtEnd { assert!(commitment_signed.is_none()); } else { assert!(commitment_signed.is_some()); @@ -394,7 +510,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) { dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment); dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id))); - if test_case == 0 { + if test_case == UnblockSignerAcrossDisconnectCase::AtEnd { let (_, _, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src); assert!(commitment_signed.is_some()); } else {