Skip to content

Commit

Permalink
Support receiving payments to blinded paths.
Browse files Browse the repository at this point in the history
Error handling will be completed in later commit(s).
  • Loading branch information
valentinewallace committed Sep 8, 2023
1 parent b80b83e commit c397e22
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 7 deletions.
60 changes: 60 additions & 0 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.

use bitcoin::secp256k1::Secp256k1;
use crate::blinded_path::BlindedPath;
use crate::blinded_path::payment::{PaymentConstraints, ReceiveTlvs};
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
use crate::ln::functional_test_utils::*;
use crate::ln::outbound_payment::Retry;
use crate::prelude::*;
use crate::routing::router::{PaymentParameters, RouteParameters};

#[test]
fn one_hop_blinded_path() {
do_one_hop_blinded_path(true);
do_one_hop_blinded_path(false);
}

fn do_one_hop_blinded_path(success: bool) {
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 chan_upd = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0).0.contents;

let amt_msat = 5000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
let payee_tlvs = ReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
htlc_minimum_msat: chan_upd.htlc_minimum_msat,
},
};
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPath::new_for_payment(
&[], nodes[1].node.get_our_node_id(), payee_tlvs, chan_upd.htlc_maximum_msat,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();

let route_params = RouteParameters {
payment_params: PaymentParameters::blinded(vec![blinded_path]),
final_value_msat: amt_msat
};
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(),
PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
check_added_monitors(&nodes[0], 1);
pass_along_route(&nodes[0], &[&[&nodes[1]]], amt_msat, payment_hash, payment_secret);
if success {
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
} else {
fail_payment(&nodes[0], &[&nodes[1]], payment_hash);
}
}
35 changes: 28 additions & 7 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::constants::{genesis_block, ChainHash};
use bitcoin::network::constants::Network;

use bitcoin::hashes::Hash;
use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hash_types::{BlockHash, Txid};

use bitcoin::secp256k1::{SecretKey,PublicKey};
use bitcoin::secp256k1::{PublicKey, Scalar, SecretKey};
use bitcoin::secp256k1::Secp256k1;
use bitcoin::{LockTime, secp256k1, Sequence};

Expand All @@ -49,7 +50,7 @@ use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Pa
use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
use crate::ln::msgs;
use crate::ln::onion_utils;
use crate::ln::onion_utils::HTLCFailReason;
use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
#[cfg(test)]
use crate::ln::outbound_payment;
Expand Down Expand Up @@ -2763,13 +2764,26 @@ where
payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata, ..
} =>
(payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata),
msgs::InboundOnionPayload::Forward { .. } =>
msgs::InboundOnionPayload::BlindedReceive {
amt_msat, total_msat, outgoing_cltv_value, payment_secret, ..
} => {
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
(Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None)
}
msgs::InboundOnionPayload::Forward { .. } => {
return Err(InboundOnionErr {
err_code: 0x4000|22,
err_data: Vec::new(),
msg: "Got non final data with an HMAC of 0",
}),
_ => todo!()
})
},
msgs::InboundOnionPayload::BlindedForward { .. } => {
return Err(InboundOnionErr {
msg: "Got blinded non final data with an HMAC of 0",
err_code: INVALID_ONION_BLINDING,
err_data: vec![0; 32],
})
},
};
// final_incorrect_cltv_expiry
if outgoing_cltv_value > cltv_expiry {
Expand Down Expand Up @@ -2882,8 +2896,15 @@ where
return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
}

let blinded_node_id_tweak = msg.blinding_point.map(|bp| {
let blinded_tlvs_ss = self.node_signer.ecdh(
Recipient::Node, &bp, None).unwrap().secret_bytes();
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
hmac.input(blinded_tlvs_ss.as_ref());
Scalar::from_be_bytes(Hmac::from_engine(hmac).into_inner()).unwrap()
});
let shared_secret = self.node_signer.ecdh(
Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), None
Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref()
).unwrap().secret_bytes();

if msg.onion_routing_packet.version != 0 {
Expand Down
3 changes: 3 additions & 0 deletions lightning/src/ln/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub mod wire;
// without the node parameter being mut. This is incorrect, and thus newer rustcs will complain
// about an unnecessary mut. Thus, we silence the unused_mut warning in two test modules below.

#[cfg(test)]
#[allow(unused_mut)]
mod blinded_payment_tests;
#[cfg(test)]
#[allow(unused_mut)]
mod functional_tests;
Expand Down
2 changes: 2 additions & 0 deletions lightning/src/ln/onion_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_o
/// the hops can be of variable length.
pub(crate) const ONION_DATA_LEN: usize = 20*65;

pub(super) const INVALID_ONION_BLINDING: u16 = 0x8000 | 0x4000 | 24;

#[inline]
fn shift_slice_right(arr: &mut [u8], amt: usize) {
for i in (amt..arr.len()).rev() {
Expand Down

0 comments on commit c397e22

Please sign in to comment.