Skip to content

Commit 0328be3

Browse files
Implement utilities for keysending to private nodes
1 parent 2d94401 commit 0328be3

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

lightning/src/ln/features.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,18 @@ impl InvoiceFeatures {
400400
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
401401
self.to_context_internal()
402402
}
403+
404+
/// Getting a route for a keysend payment to a private node requires providing the payee's
405+
/// features (since they were not announced in a node announcement). However, keysend payments
406+
/// don't have an invoice to pull the payee's features from, so this method is provided for use in
407+
/// [`get_keysend_route`], thus omitting the need for payers to manually construct an
408+
/// `InvoiceFeatures` for [`get_route`].
409+
///
410+
/// [`get_keysend_route`]: crate::routing::router::get_keysend_route
411+
/// [`get_route`]: crate::routing::router::get_route
412+
pub(crate) fn for_keysend() -> InvoiceFeatures {
413+
InvoiceFeatures::empty().set_variable_length_onion_optional()
414+
}
403415
}
404416

405417
impl ToBase32 for InvoiceFeatures {

lightning/src/ln/functional_tests.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOr
2323
use ln::channel::{Channel, ChannelError};
2424
use ln::{chan_utils, onion_utils};
2525
use ln::chan_utils::HTLC_SUCCESS_TX_WEIGHT;
26-
use routing::router::{Route, RouteHop, RouteHint, RouteHintHop, get_route};
26+
use routing::router::{Route, RouteHop, RouteHint, RouteHintHop, get_route, get_keysend_route};
2727
use routing::network_graph::RoutingFees;
2828
use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
2929
use ln::msgs;
@@ -9626,3 +9626,33 @@ fn test_keysend_payments_to_public_node() {
96269626
pass_along_path(&nodes[0], &path, 10000, payment_hash, PaymentSecret([0; 32]), event, true, Some(test_preimage));
96279627
claim_payment(&nodes[0], &path, test_preimage);
96289628
}
9629+
9630+
#[test]
9631+
fn test_keysend_payments_to_private_node() {
9632+
let chanmon_cfgs = create_chanmon_cfgs(2);
9633+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9634+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9635+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9636+
9637+
let payer_pubkey = nodes[0].node.get_our_node_id();
9638+
let payee_pubkey = nodes[1].node.get_our_node_id();
9639+
nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() });
9640+
nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() });
9641+
9642+
let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
9643+
let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap();
9644+
let first_hops = nodes[0].node.list_usable_channels();
9645+
let route = get_keysend_route(&payer_pubkey, &network_graph, &payee_pubkey,
9646+
Some(&first_hops.iter().collect::<Vec<_>>()), &vec![], 10000, 40,
9647+
nodes[0].logger).unwrap();
9648+
9649+
let test_preimage = PaymentPreimage([42; 32]);
9650+
let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage)).unwrap();
9651+
check_added_monitors!(nodes[0], 1);
9652+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9653+
assert_eq!(events.len(), 1);
9654+
let event = events.pop().unwrap();
9655+
let path = vec![&nodes[1]];
9656+
pass_along_path(&nodes[0], &path, 10000, payment_hash, PaymentSecret([0; 32]), event, true, Some(test_preimage));
9657+
claim_payment(&nodes[0], &path, test_preimage);
9658+
}

lightning/src/routing/router.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,18 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
327327
}
328328
}
329329

330+
/// Gets a keysend route from us (payer) to the given target node (payee). This is needed because
331+
/// keysend payments do not have an invoice from which to pull the payee's supported features, which
332+
/// makes it tricky to otherwise supply the `payee_features` parameter of `get_route`.
333+
pub fn get_keysend_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, payee:
334+
&PublicKey, first_hops: Option<&[&ChannelDetails]>, last_hops: &[&RouteHint],
335+
final_value_msat: u64, final_cltv: u32, logger: L) -> Result<Route,
336+
LightningError> where L::Target: Logger {
337+
let invoice_features = InvoiceFeatures::for_keysend();
338+
get_route(our_node_id, network, payee, Some(invoice_features), first_hops, last_hops,
339+
final_value_msat, final_cltv, logger)
340+
}
341+
330342
/// Gets a route from us (payer) to the given target node (payee).
331343
///
332344
/// If the payee provided features in their invoice, they should be provided via payee_features.

0 commit comments

Comments
 (0)