Skip to content

Commit

Permalink
Implement utilities for keysending to private nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinewallace committed Jul 4, 2021
1 parent 5ae13dc commit a003460
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
12 changes: 12 additions & 0 deletions lightning/src/ln/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,18 @@ impl InvoiceFeatures {
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
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 {
Expand Down
32 changes: 31 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,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};
Expand Down Expand Up @@ -9419,3 +9419,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<_>>()), &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);
}
12 changes: 12 additions & 0 deletions lightning/src/routing/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,18 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
}
}

/// 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<L: Deref>(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<Route,
LightningError> 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.
Expand Down

0 comments on commit a003460

Please sign in to comment.