From: Valentine Wallace Date: Fri, 25 Jun 2021 23:43:55 +0000 (-0400) Subject: Implement utilities for keysending to private nodes X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=de9d7f7b2bea717cadfb1ea1fc6de3622d6c8751;p=rust-lightning Implement utilities for keysending to private nodes --- diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 9ebcc7010..10480c4dd 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -420,6 +420,18 @@ impl InvoiceFeatures { pub(crate) fn to_context(&self) -> Features { self.to_context_internal() } + + /// Getting a route for a keysend payment to a private node requires providing the payee's + /// features (since they were not announced in a node announcement). However, keysend payments + /// don't have an invoice to pull the payee's features from, so this method is provided for use in + /// [`get_keysend_route`], thus omitting the need for payers to manually construct an + /// `InvoiceFeatures` for [`get_route`]. + /// + /// [`get_keysend_route`]: crate::routing::router::get_keysend_route + /// [`get_route`]: crate::routing::router::get_route + pub(crate) fn for_keysend() -> InvoiceFeatures { + InvoiceFeatures::empty().set_variable_length_onion_optional() + } } impl ToBase32 for InvoiceFeatures { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 673c299b5..687322c6b 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -23,7 +23,7 @@ use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC}; use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA}; use ln::channel::{Channel, ChannelError}; use ln::{chan_utils, onion_utils}; -use routing::router::{Route, RouteHop, get_route}; +use routing::router::{Route, RouteHop, get_route, get_keysend_route}; use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; use ln::msgs; use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction}; @@ -9324,3 +9324,33 @@ fn test_keysend_payments_to_public_node() { pass_along_path(&nodes[0], &path, 10000, payment_hash, PaymentSecret([0; 32]), event, true, Some(test_preimage)); claim_payment(&nodes[0], &path, test_preimage); } + +#[test] +fn test_keysend_payments_to_private_node() { + 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 payer_pubkey = nodes[0].node.get_our_node_id(); + let payee_pubkey = nodes[1].node.get_our_node_id(); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + + let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); + let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap(); + let first_hops = nodes[0].node.list_usable_channels(); + let route = get_keysend_route(&payer_pubkey, &network_graph, &payee_pubkey, + Some(&first_hops.iter().collect::>()), &vec![], 10000, 40, + nodes[0].logger).unwrap(); + + let test_preimage = PaymentPreimage([42; 32]); + let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage)).unwrap(); + check_added_monitors!(nodes[0], 1); + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + let path = vec![&nodes[1]]; + pass_along_path(&nodes[0], &path, 10000, payment_hash, PaymentSecret([0; 32]), event, true, Some(test_preimage)); + claim_payment(&nodes[0], &path, test_preimage); +} diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 12374bad5..25edb5699 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -327,6 +327,18 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option { } } +/// Gets a keysend route from us (payer) to the given target node (payee). This is needed because +/// keysend payments do not have an invoice from which to pull the payee's supported features, which +/// makes it tricky to otherwise supply the `payee_features` parameter of `get_route`. +pub fn get_keysend_route(our_node_id: &PublicKey, network: &NetworkGraph, payee: + &PublicKey, first_hops: Option<&[&ChannelDetails]>, last_hops: &[&RouteHint], + final_value_msat: u64, final_cltv: u32, logger: L) -> Result where L::Target: Logger { + let invoice_features = InvoiceFeatures::for_keysend(); + get_route(our_node_id, network, payee, Some(invoice_features), first_hops, last_hops, + final_value_msat, final_cltv, logger) +} + /// Gets a route from us (payer) to the given target node (payee). /// /// If the payee provided features in their invoice, they should be provided via payee_features.