Skip to content

Commit a4fe071

Browse files
Implement sending + receiving keysend payments
1 parent 6c7a6aa commit a4fe071

File tree

4 files changed

+96
-21
lines changed

4 files changed

+96
-21
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,14 +1434,22 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
14341434
return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry));
14351435
}
14361436

1437-
let (payment_data, keysend_preimage) = match next_hop_data.format {
1437+
let (mut payment_data, keysend_preimage) = match next_hop_data.format {
14381438
msgs::OnionHopDataFormat::Legacy { .. } => (None, None),
14391439
msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]),
14401440
msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => (payment_data, keysend_preimage),
14411441
};
14421442

14431443
if payment_data.is_none() {
1444-
return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]);
1444+
match keysend_preimage {
1445+
Some(_) => {
1446+
payment_data = Some(msgs::FinalOnionHopData {
1447+
payment_secret: PaymentSecret([0; 32]),
1448+
total_msat: msg.amount_msat
1449+
});
1450+
},
1451+
None => return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0])
1452+
}
14451453
}
14461454

14471455
// Note that we could obviously respond immediately with an update_fulfill_htlc
@@ -1622,15 +1630,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16221630
}
16231631

16241632
// Only public for testing, this should otherwise never be called direcly
1625-
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32) -> Result<(), APIError> {
1633+
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
16261634
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
16271635
let prng_seed = self.keys_manager.get_secure_random_bytes();
16281636
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
16291637
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
16301638

16311639
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
16321640
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
1633-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height)?;
1641+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height, keysend_preimage)?;
16341642
if onion_utils::route_size_insane(&onion_payloads) {
16351643
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
16361644
}
@@ -1738,6 +1746,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
17381746
/// bit set (either as required or as available). If multiple paths are present in the Route,
17391747
/// we assume the invoice had the basic_mpp feature set.
17401748
pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<(), PaymentSendFailure> {
1749+
self.send_payment_internal(route, payment_hash, payment_secret, None)
1750+
}
1751+
1752+
fn send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, keysend_preimage: Option<PaymentPreimage>) -> Result<(), PaymentSendFailure> {
17411753
if route.paths.len() < 1 {
17421754
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
17431755
}
@@ -1771,7 +1783,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
17711783
let cur_height = self.best_block.read().unwrap().height() + 1;
17721784
let mut results = Vec::new();
17731785
for path in route.paths.iter() {
1774-
results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height));
1786+
results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height, &keysend_preimage));
17751787
}
17761788
let mut has_ok = false;
17771789
let mut has_err = false;
@@ -1795,6 +1807,23 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
17951807
}
17961808
}
17971809

1810+
/// Send a spontaneous payment, which is a payment that does not require the recipient to have
1811+
/// generated an invoice. Optionally, you may specify the preimage. If you do choose to specify
1812+
/// the preimage, it must be a secure, random value that no intermediate node would be able to
1813+
/// guess -- otherwise, an intermediate node may claim the payment and it will never reach the
1814+
/// recipient.
1815+
pub fn send_spontaneous_payment(&self, route: &Route, payment_preimage: Option<PaymentPreimage>) -> Result<PaymentHash, PaymentSendFailure> {
1816+
let preimage = match payment_preimage {
1817+
Some(p) => p,
1818+
None => PaymentPreimage(self.keys_manager.get_secure_random_bytes()),
1819+
};
1820+
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
1821+
match self.send_payment_internal(route, payment_hash, &None, Some(preimage)) {
1822+
Ok(()) => Ok(payment_hash),
1823+
Err(e) => Err(e)
1824+
}
1825+
}
1826+
17981827
/// Handles the generation of a funding transaction, optionally (for tests) with a function
17991828
/// which checks the correctness of the funding transaction given the associated channel.
18001829
fn funding_transaction_generated_intern<FundingOutput: Fn(&Channel<Signer>, &Transaction) -> Result<OutPoint, APIError>>
@@ -3057,6 +3086,23 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
30573086
let (pending_forward_info, mut channel_state_lock) = self.decode_update_add_htlc_onion(msg);
30583087
let channel_state = &mut *channel_state_lock;
30593088

3089+
// If we're receiving a keysend payment, then no payment will have been added to
3090+
// `self.pending_inbound_payments` in preparation to receive said payment. Thus, if a
3091+
// keysend_preimage is present, add the pending inbound payment now.
3092+
match pending_forward_info {
3093+
PendingHTLCStatus::Forward(PendingHTLCInfo { ref routing, .. }) => {
3094+
match routing {
3095+
PendingHTLCRouting::Receive { payment_data, keysend_preimage: Some(preimage), .. } => {
3096+
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner());
3097+
let default_invoice_expiry_secs = 60 * 60; // 1 hour
3098+
self.set_payment_hash_secret_map(hash, Some(preimage.clone()), Some(payment_data.payment_secret), Some(payment_data.total_msat), default_invoice_expiry_secs, 0).unwrap();
3099+
},
3100+
_ => {}
3101+
}
3102+
},
3103+
_ => {}
3104+
}
3105+
30603106
match channel_state.by_id.entry(msg.channel_id) {
30613107
hash_map::Entry::Occupied(mut chan) => {
30623108
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
@@ -3586,10 +3632,13 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
35863632
}
35873633
}
35883634

3589-
fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
3635+
fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, payment_secret: Option<PaymentSecret>, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
35903636
assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106
35913637

3592-
let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes());
3638+
let payment_secret = match payment_secret {
3639+
Some(secret) => secret,
3640+
None => PaymentSecret(self.keys_manager.get_secure_random_bytes())
3641+
};
35933642

35943643
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
35953644
let mut payment_secrets = self.pending_inbound_payments.lock().unwrap();
@@ -3633,7 +3682,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
36333682
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
36343683

36353684
(payment_hash,
3636-
self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs, user_payment_id)
3685+
self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), None, min_value_msat, invoice_expiry_delta_secs, user_payment_id)
36373686
.expect("RNG Generated Duplicate PaymentHash"))
36383687
}
36393688

@@ -3683,7 +3732,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
36833732
/// [`PaymentReceived`]: events::Event::PaymentReceived
36843733
/// [`PaymentReceived::user_payment_id`]: events::Event::PaymentReceived::user_payment_id
36853734
pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
3686-
self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id)
3735+
self.set_payment_hash_secret_map(payment_hash, None, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id)
36873736
}
36883737

36893738
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]

lightning/src/ln/functional_tests.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ fn test_fee_spike_violation_fails_htlc() {
15911591
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
15921592

15931593
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1594-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), cur_height).unwrap();
1594+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), cur_height, &None).unwrap();
15951595
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
15961596
let msg = msgs::UpdateAddHTLC {
15971597
channel_id: chan.2,
@@ -1741,7 +1741,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
17411741
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
17421742
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
17431743
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1744-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 1000, &Some(payment_secret), cur_height).unwrap();
1744+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 1000, &Some(payment_secret), cur_height, &None).unwrap();
17451745
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
17461746
let msg = msgs::UpdateAddHTLC {
17471747
channel_id: chan.2,
@@ -1854,7 +1854,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
18541854
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
18551855
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
18561856
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
1857-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height).unwrap();
1857+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height, &None).unwrap();
18581858
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
18591859
let msg = msgs::UpdateAddHTLC {
18601860
channel_id: chan.2,
@@ -3388,7 +3388,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
33883388
let current_height = nodes[1].node.best_block.read().unwrap().height() + 1;
33893389
let net_graph_msg_handler = &nodes[1].net_graph_msg_handler;
33903390
let route = get_route(&nodes[1].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[0].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 50_000, TEST_FINAL_CLTV, &logger).unwrap();
3391-
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), current_height).unwrap();
3391+
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), current_height, &None).unwrap();
33923392
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
33933393
let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
33943394

@@ -4131,7 +4131,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
41314131
// Use the utility function send_payment_along_path to send the payment with MPP data which
41324132
// indicates there are more HTLCs coming.
41334133
let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
4134-
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200000, cur_height).unwrap();
4134+
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200000, cur_height, &None).unwrap();
41354135
check_added_monitors!(nodes[0], 1);
41364136
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
41374137
assert_eq!(events.len(), 1);
@@ -6766,7 +6766,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
67666766

67676767
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
67686768
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
6769-
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height).unwrap();
6769+
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height, &None).unwrap();
67706770
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
67716771

67726772
let mut msg = msgs::UpdateAddHTLC {
@@ -9298,3 +9298,29 @@ fn test_invalid_funding_tx() {
92989298
} else { panic!(); }
92999299
assert_eq!(nodes[1].node.list_channels().len(), 0);
93009300
}
9301+
9302+
#[test]
9303+
fn test_keysend_payments() {
9304+
let chanmon_cfgs = create_chanmon_cfgs(2);
9305+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9306+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9307+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9308+
9309+
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
9310+
let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap();
9311+
let payer_pubkey = nodes[0].node.get_our_node_id();
9312+
let payee_pubkey = nodes[1].node.get_our_node_id();
9313+
let route = get_route(&payer_pubkey, &network_graph, &payee_pubkey, None,
9314+
None, &vec![], 10000, 40,
9315+
nodes[0].logger).unwrap();
9316+
9317+
let test_preimage = PaymentPreimage([42; 32]);
9318+
let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage)).unwrap();
9319+
check_added_monitors!(nodes[0], 1);
9320+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9321+
assert_eq!(events.len(), 1);
9322+
let event = events.pop().unwrap();
9323+
let path = vec![&nodes[1]];
9324+
pass_along_path(&nodes[0], &path, 10000, payment_hash, PaymentSecret([0; 32]), event, true, Some(test_preimage));
9325+
claim_payment(&nodes[0], &path, test_preimage);
9326+
}

lightning/src/ln/onion_route_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ fn test_onion_failure() {
280280
let session_priv = SecretKey::from_slice(&[3; 32]).unwrap();
281281
let cur_height = nodes[0].best_block_info().1 + 1;
282282
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
283-
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height).unwrap();
283+
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height, &None).unwrap();
284284
let mut new_payloads = Vec::new();
285285
for payload in onion_payloads.drain(..) {
286286
new_payloads.push(BogusOnionHopData::new(payload));
@@ -296,7 +296,7 @@ fn test_onion_failure() {
296296
let session_priv = SecretKey::from_slice(&[3; 32]).unwrap();
297297
let cur_height = nodes[0].best_block_info().1 + 1;
298298
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
299-
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height).unwrap();
299+
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height, &None).unwrap();
300300
let mut new_payloads = Vec::new();
301301
for payload in onion_payloads.drain(..) {
302302
new_payloads.push(BogusOnionHopData::new(payload));
@@ -490,7 +490,7 @@ fn test_onion_failure() {
490490
let height = nodes[2].best_block_info().1;
491491
route.paths[0][1].cltv_expiry_delta += CLTV_FAR_FAR_AWAY + route.paths[0][0].cltv_expiry_delta + 1;
492492
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
493-
let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, height).unwrap();
493+
let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, height, &None).unwrap();
494494
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
495495
msg.cltv_expiry = htlc_cltv;
496496
msg.onion_routing_packet = onion_packet;

lightning/src/ln/onion_utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10-
use ln::{PaymentHash, PaymentSecret};
10+
use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1111
use ln::channelmanager::HTLCSource;
1212
use ln::msgs;
1313
use routing::router::RouteHop;
@@ -119,7 +119,7 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T
119119
}
120120

121121
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
122-
pub(super) fn build_onion_payloads(path: &Vec<RouteHop>, total_msat: u64, payment_secret_option: &Option<PaymentSecret>, starting_htlc_offset: u32) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
122+
pub(super) fn build_onion_payloads(path: &Vec<RouteHop>, total_msat: u64, payment_secret_option: &Option<PaymentSecret>, starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
123123
let mut cur_value_msat = 0u64;
124124
let mut cur_cltv = starting_htlc_offset;
125125
let mut last_short_channel_id = 0;
@@ -141,7 +141,7 @@ pub(super) fn build_onion_payloads(path: &Vec<RouteHop>, total_msat: u64, paymen
141141
total_msat,
142142
})
143143
} else { None },
144-
keysend_preimage: None,
144+
keysend_preimage: *keysend_preimage,
145145
}
146146
} else {
147147
msgs::OnionHopDataFormat::NonFinalNode {

0 commit comments

Comments
 (0)