|
13 | 13 |
|
14 | 14 | use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
|
15 | 15 | use crate::chain::channelmonitor::{ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
|
16 |
| -use crate::sign::EntropySource; |
| 16 | +use crate::sign::{EntropySource, NodeSigner, PhantomKeysManager, Recipient}; |
17 | 17 | use crate::chain::transaction::OutPoint;
|
18 | 18 | use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
|
19 | 19 | use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
|
@@ -1673,6 +1673,127 @@ fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) {
|
1673 | 1673 | Some(Some(total_fee_msat - skimmed_fee_msat * num_mpp_parts as u64)), true);
|
1674 | 1674 | }
|
1675 | 1675 |
|
| 1676 | +#[test] |
| 1677 | +fn underpay_to_phantom() { |
| 1678 | + // Weird case, but it's possible for a user to set up their route hints as: |
| 1679 | + // Liquidity provider -(intercept scid)-> user -(phantom scid)-> phantom |
| 1680 | + let mut chanmon_cfgs = create_chanmon_cfgs(3); |
| 1681 | + let seed = [42u8; 32]; |
| 1682 | + let cross_node_seed = [43u8; 32]; |
| 1683 | + chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed, 43, 44, &cross_node_seed); |
| 1684 | + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); |
| 1685 | + let mut intercept_forwards_config = test_default_channel_config(); |
| 1686 | + intercept_forwards_config.accept_intercept_htlcs = true; |
| 1687 | + let mut underpay_config = test_default_channel_config(); |
| 1688 | + underpay_config.channel_config.accept_underpaying_htlcs = true; |
| 1689 | + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(underpay_config)]); |
| 1690 | + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); |
| 1691 | + |
| 1692 | + let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 2_000_000, 0); |
| 1693 | + let channel_id = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 2_000_000, 0).0.channel_id; |
| 1694 | + let amt_msat = 900_000; |
| 1695 | + let skimmed_fee_msat = 20; |
| 1696 | + let route_hint = vec!(RouteHint(vec![RouteHintHop { |
| 1697 | + src_node_id: nodes[1].node.get_our_node_id(), |
| 1698 | + short_channel_id: nodes[1].node.get_intercept_scid(), |
| 1699 | + fees: RoutingFees { |
| 1700 | + base_msat: 1000, |
| 1701 | + proportional_millionths: 0, |
| 1702 | + }, |
| 1703 | + cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA, |
| 1704 | + htlc_minimum_msat: None, |
| 1705 | + htlc_maximum_msat: None, |
| 1706 | + }, RouteHintHop { |
| 1707 | + src_node_id: nodes[2].node.get_our_node_id(), |
| 1708 | + short_channel_id: nodes[2].node.get_phantom_scid(), |
| 1709 | + fees: RoutingFees { |
| 1710 | + base_msat: 0, |
| 1711 | + proportional_millionths: 0, |
| 1712 | + }, |
| 1713 | + cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA, |
| 1714 | + htlc_minimum_msat: None, |
| 1715 | + htlc_maximum_msat: None, |
| 1716 | + }])); |
| 1717 | + let phantom_node_id = chanmon_cfgs[2].keys_manager.backing.get_node_id(Recipient::PhantomNode).unwrap(); |
| 1718 | + let payment_params = PaymentParameters::from_node_id(phantom_node_id, TEST_FINAL_CLTV) |
| 1719 | + .with_route_hints(route_hint).unwrap() |
| 1720 | + .with_bolt11_features(nodes[2].node.invoice_features()).unwrap(); |
| 1721 | + let route_params = RouteParameters { payment_params, final_value_msat: amt_msat, }; |
| 1722 | + let (payment_hash, payment_secret) = nodes[2].node.create_inbound_payment(Some(amt_msat), 60 * 60, None).unwrap(); |
| 1723 | + nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret), |
| 1724 | + PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); |
| 1725 | + check_added_monitors!(nodes[0], 1); |
| 1726 | + let mut events: Vec<SendEvent> = nodes[0].node.get_and_clear_pending_msg_events().into_iter().map(|e| SendEvent::from_event(e)).collect(); |
| 1727 | + assert_eq!(events.len(), 1); |
| 1728 | + |
| 1729 | + nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &events[0].msgs[0]); |
| 1730 | + do_commitment_signed_dance(&nodes[1], &nodes[0], &events[0].commitment_msg, false, true); |
| 1731 | + |
| 1732 | + let events = nodes[1].node.get_and_clear_pending_events(); |
| 1733 | + assert_eq!(events.len(), 1); |
| 1734 | + let (intercept_id, expected_outbound_amt_msat) = match events[0] { |
| 1735 | + crate::events::Event::HTLCIntercepted { |
| 1736 | + intercept_id, expected_outbound_amount_msat, payment_hash: pmt_hash, .. |
| 1737 | + } => { |
| 1738 | + assert_eq!(pmt_hash, payment_hash); |
| 1739 | + assert_eq!(expected_outbound_amount_msat, amt_msat); |
| 1740 | + (intercept_id, expected_outbound_amount_msat) |
| 1741 | + }, |
| 1742 | + _ => panic!() |
| 1743 | + }; |
| 1744 | + nodes[1].node.forward_intercepted_htlc(intercept_id, &channel_id, |
| 1745 | + nodes[2].node.get_our_node_id(), expected_outbound_amt_msat - skimmed_fee_msat).unwrap(); |
| 1746 | + expect_pending_htlcs_forwardable!(nodes[1]); |
| 1747 | + let payment_event = { |
| 1748 | + { |
| 1749 | + let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap(); |
| 1750 | + assert_eq!(added_monitors.len(), 1); |
| 1751 | + added_monitors.clear(); |
| 1752 | + } |
| 1753 | + let mut events = nodes[1].node.get_and_clear_pending_msg_events(); |
| 1754 | + assert_eq!(events.len(), 1); |
| 1755 | + SendEvent::from_event(events.remove(0)) |
| 1756 | + }; |
| 1757 | + nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]); |
| 1758 | + do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event.commitment_msg, false, true); |
| 1759 | + expect_pending_htlcs_forwardable!(nodes[2]); |
| 1760 | + |
| 1761 | + // Claim the payment and check that the skimmed fee is as expected. |
| 1762 | + let payment_preimage = nodes[2].node.get_payment_preimage(payment_hash, payment_secret).unwrap(); |
| 1763 | + let events = nodes[2].node.get_and_clear_pending_events(); |
| 1764 | + assert_eq!(events.len(), 2); |
| 1765 | + match events[0] { |
| 1766 | + crate::events::Event::PendingHTLCsForwardable { .. } => {}, |
| 1767 | + _ => { panic!() } |
| 1768 | + } |
| 1769 | + match events[1] { |
| 1770 | + crate::events::Event::PaymentClaimable { |
| 1771 | + ref payment_hash, ref purpose, amount_msat, counterparty_skimmed_fee_msat, receiver_node_id, .. |
| 1772 | + } => { |
| 1773 | + assert_eq!(payment_hash, payment_hash); |
| 1774 | + assert_eq!(skimmed_fee_msat, counterparty_skimmed_fee_msat); |
| 1775 | + assert_eq!(amt_msat - skimmed_fee_msat, amount_msat); |
| 1776 | + assert_eq!(phantom_node_id, receiver_node_id.unwrap()); |
| 1777 | + match purpose { |
| 1778 | + crate::events::PaymentPurpose::InvoicePayment { payment_preimage: ev_payment_preimage, |
| 1779 | + payment_secret: ev_payment_secret, .. } => |
| 1780 | + { |
| 1781 | + assert_eq!(payment_preimage, ev_payment_preimage.unwrap()); |
| 1782 | + assert_eq!(payment_secret, *ev_payment_secret); |
| 1783 | + }, |
| 1784 | + _ => panic!(), |
| 1785 | + } |
| 1786 | + }, |
| 1787 | + _ => panic!("Unexpected event"), |
| 1788 | + } |
| 1789 | + let total_fee_msat = do_claim_payment_along_route_with_extra_penultimate_hop_fees( |
| 1790 | + &nodes[0], &[&[&nodes[1], &nodes[2]]], &vec![skimmed_fee_msat as u32; 1][..], false, |
| 1791 | + payment_preimage); |
| 1792 | + // The sender doesn't know that the penultimate hop took an extra fee. |
| 1793 | + expect_payment_sent(&nodes[0], payment_preimage, |
| 1794 | + Some(Some(total_fee_msat - skimmed_fee_msat)), true); |
| 1795 | +} |
| 1796 | + |
1676 | 1797 | #[derive(PartialEq)]
|
1677 | 1798 | enum AutoRetry {
|
1678 | 1799 | Success,
|
|
0 commit comments