Skip to content

Commit 9856fb6

Browse files
Merge pull request #2688 from valentinewallace/2023-10-multihop-blinded-recv
Support receiving to multi-hop blinded paths
2 parents 0dbf17b + 6b66271 commit 9856fb6

File tree

10 files changed

+757
-102
lines changed

10 files changed

+757
-102
lines changed

fuzz/src/onion_hop_data.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@ use lightning::util::test_utils;
1616
#[inline]
1717
pub fn onion_hop_data_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
1818
use lightning::util::ser::ReadableArgs;
19+
use bitcoin::secp256k1::PublicKey;
1920
let mut r = ::std::io::Cursor::new(data);
2021
let node_signer = test_utils::TestNodeSigner::new(test_utils::privkey(42));
21-
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<&&test_utils::TestNodeSigner>>::read(&mut r, &&node_signer);
22+
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<(Option<PublicKey>, &&test_utils::TestNodeSigner)>>::read(&mut r, (None, &&node_signer));
2223
}
2324

2425
#[no_mangle]
2526
pub extern "C" fn onion_hop_data_run(data: *const u8, datalen: usize) {
2627
use lightning::util::ser::ReadableArgs;
28+
use bitcoin::secp256k1::PublicKey;
2729
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
2830
let mut r = ::std::io::Cursor::new(data);
2931
let node_signer = test_utils::TestNodeSigner::new(test_utils::privkey(42));
30-
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<&&test_utils::TestNodeSigner>>::read(&mut r, &&node_signer);
32+
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<(Option<PublicKey>, &&test_utils::TestNodeSigner)>>::read(&mut r, (None, &&node_signer));
3133
}

lightning/src/blinded_path/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl BlindedPath {
105105
///
106106
/// [`ForwardTlvs`]: crate::blinded_path::payment::ForwardTlvs
107107
// TODO: make all payloads the same size with padding + add dummy hops
108-
pub(crate) fn new_for_payment<ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification>(
108+
pub fn new_for_payment<ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification>(
109109
intermediate_nodes: &[payment::ForwardNode], payee_node_id: PublicKey,
110110
payee_tlvs: payment::ReceiveTlvs, htlc_maximum_msat: u64, entropy_source: &ES,
111111
secp_ctx: &Secp256k1<T>

lightning/src/ln/blinded_payment_tests.rs

+284-16
Large diffs are not rendered by default.

lightning/src/ln/channel.rs

+156-22
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ enum HTLCUpdateAwaitingACK {
259259
htlc_id: u64,
260260
err_packet: msgs::OnionErrorPacket,
261261
},
262+
FailMalformedHTLC {
263+
htlc_id: u64,
264+
failure_code: u16,
265+
sha256_of_onion: [u8; 32],
266+
},
262267
}
263268

264269
macro_rules! define_state_flags {
@@ -2518,6 +2523,64 @@ struct CommitmentTxInfoCached {
25182523
feerate: u32,
25192524
}
25202525

2526+
/// Contents of a wire message that fails an HTLC backwards. Useful for [`Channel::fail_htlc`] to
2527+
/// fail with either [`msgs::UpdateFailMalformedHTLC`] or [`msgs::UpdateFailHTLC`] as needed.
2528+
trait FailHTLCContents {
2529+
type Message: FailHTLCMessageName;
2530+
fn to_message(self, htlc_id: u64, channel_id: ChannelId) -> Self::Message;
2531+
fn to_inbound_htlc_state(self) -> InboundHTLCState;
2532+
fn to_htlc_update_awaiting_ack(self, htlc_id: u64) -> HTLCUpdateAwaitingACK;
2533+
}
2534+
impl FailHTLCContents for msgs::OnionErrorPacket {
2535+
type Message = msgs::UpdateFailHTLC;
2536+
fn to_message(self, htlc_id: u64, channel_id: ChannelId) -> Self::Message {
2537+
msgs::UpdateFailHTLC { htlc_id, channel_id, reason: self }
2538+
}
2539+
fn to_inbound_htlc_state(self) -> InboundHTLCState {
2540+
InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(self))
2541+
}
2542+
fn to_htlc_update_awaiting_ack(self, htlc_id: u64) -> HTLCUpdateAwaitingACK {
2543+
HTLCUpdateAwaitingACK::FailHTLC { htlc_id, err_packet: self }
2544+
}
2545+
}
2546+
impl FailHTLCContents for (u16, [u8; 32]) {
2547+
type Message = msgs::UpdateFailMalformedHTLC; // (failure_code, sha256_of_onion)
2548+
fn to_message(self, htlc_id: u64, channel_id: ChannelId) -> Self::Message {
2549+
msgs::UpdateFailMalformedHTLC {
2550+
htlc_id,
2551+
channel_id,
2552+
failure_code: self.0,
2553+
sha256_of_onion: self.1
2554+
}
2555+
}
2556+
fn to_inbound_htlc_state(self) -> InboundHTLCState {
2557+
InboundHTLCState::LocalRemoved(
2558+
InboundHTLCRemovalReason::FailMalformed((self.1, self.0))
2559+
)
2560+
}
2561+
fn to_htlc_update_awaiting_ack(self, htlc_id: u64) -> HTLCUpdateAwaitingACK {
2562+
HTLCUpdateAwaitingACK::FailMalformedHTLC {
2563+
htlc_id,
2564+
failure_code: self.0,
2565+
sha256_of_onion: self.1
2566+
}
2567+
}
2568+
}
2569+
2570+
trait FailHTLCMessageName {
2571+
fn name() -> &'static str;
2572+
}
2573+
impl FailHTLCMessageName for msgs::UpdateFailHTLC {
2574+
fn name() -> &'static str {
2575+
"update_fail_htlc"
2576+
}
2577+
}
2578+
impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
2579+
fn name() -> &'static str {
2580+
"update_fail_malformed_htlc"
2581+
}
2582+
}
2583+
25212584
impl<SP: Deref> Channel<SP> where
25222585
SP::Target: SignerProvider,
25232586
<SP::Target as SignerProvider>::EcdsaSigner: WriteableEcdsaChannelSigner
@@ -2719,7 +2782,9 @@ impl<SP: Deref> Channel<SP> where
27192782
return UpdateFulfillFetch::DuplicateClaim {};
27202783
}
27212784
},
2722-
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
2785+
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } |
2786+
&HTLCUpdateAwaitingACK::FailMalformedHTLC { htlc_id, .. } =>
2787+
{
27232788
if htlc_id_arg == htlc_id {
27242789
log_warn!(logger, "Have preimage and want to fulfill HTLC with pending failure against channel {}", &self.context.channel_id());
27252790
// TODO: We may actually be able to switch to a fulfill here, though its
@@ -2816,6 +2881,17 @@ impl<SP: Deref> Channel<SP> where
28162881
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
28172882
}
28182883

2884+
/// Used for failing back with [`msgs::UpdateFailMalformedHTLC`]. For now, this is used when we
2885+
/// want to fail blinded HTLCs where we are not the intro node.
2886+
///
2887+
/// See [`Self::queue_fail_htlc`] for more info.
2888+
pub fn queue_fail_malformed_htlc<L: Deref>(
2889+
&mut self, htlc_id_arg: u64, failure_code: u16, sha256_of_onion: [u8; 32], logger: &L
2890+
) -> Result<(), ChannelError> where L::Target: Logger {
2891+
self.fail_htlc(htlc_id_arg, (failure_code, sha256_of_onion), true, logger)
2892+
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
2893+
}
2894+
28192895
/// We can only have one resolution per HTLC. In some cases around reconnect, we may fulfill
28202896
/// an HTLC more than once or fulfill once and then attempt to fail after reconnect. We cannot,
28212897
/// however, fail more than once as we wait for an upstream failure to be irrevocably committed
@@ -2824,8 +2900,10 @@ impl<SP: Deref> Channel<SP> where
28242900
/// If we do fail twice, we `debug_assert!(false)` and return `Ok(None)`. Thus, this will always
28252901
/// return `Ok(_)` if preconditions are met. In any case, `Err`s will only be
28262902
/// [`ChannelError::Ignore`].
2827-
fn fail_htlc<L: Deref>(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, mut force_holding_cell: bool, logger: &L)
2828-
-> Result<Option<msgs::UpdateFailHTLC>, ChannelError> where L::Target: Logger {
2903+
fn fail_htlc<L: Deref, E: FailHTLCContents + Clone>(
2904+
&mut self, htlc_id_arg: u64, err_packet: E, mut force_holding_cell: bool,
2905+
logger: &L
2906+
) -> Result<Option<E::Message>, ChannelError> where L::Target: Logger {
28292907
if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
28302908
panic!("Was asked to fail an HTLC when channel was not in an operational state");
28312909
}
@@ -2878,7 +2956,9 @@ impl<SP: Deref> Channel<SP> where
28782956
return Ok(None);
28792957
}
28802958
},
2881-
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
2959+
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } |
2960+
&HTLCUpdateAwaitingACK::FailMalformedHTLC { htlc_id, .. } =>
2961+
{
28822962
if htlc_id_arg == htlc_id {
28832963
debug_assert!(false, "Tried to fail an HTLC that was already failed");
28842964
return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID".to_owned()));
@@ -2888,24 +2968,18 @@ impl<SP: Deref> Channel<SP> where
28882968
}
28892969
}
28902970
log_trace!(logger, "Placing failure for HTLC ID {} in holding cell in channel {}.", htlc_id_arg, &self.context.channel_id());
2891-
self.context.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::FailHTLC {
2892-
htlc_id: htlc_id_arg,
2893-
err_packet,
2894-
});
2971+
self.context.holding_cell_htlc_updates.push(err_packet.to_htlc_update_awaiting_ack(htlc_id_arg));
28952972
return Ok(None);
28962973
}
28972974

2898-
log_trace!(logger, "Failing HTLC ID {} back with a update_fail_htlc message in channel {}.", htlc_id_arg, &self.context.channel_id());
2975+
log_trace!(logger, "Failing HTLC ID {} back with {} message in channel {}.", htlc_id_arg,
2976+
E::Message::name(), &self.context.channel_id());
28992977
{
29002978
let htlc = &mut self.context.pending_inbound_htlcs[pending_idx];
2901-
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone()));
2979+
htlc.state = err_packet.clone().to_inbound_htlc_state();
29022980
}
29032981

2904-
Ok(Some(msgs::UpdateFailHTLC {
2905-
channel_id: self.context.channel_id(),
2906-
htlc_id: htlc_id_arg,
2907-
reason: err_packet
2908-
}))
2982+
Ok(Some(err_packet.to_message(htlc_id_arg, self.context.channel_id())))
29092983
}
29102984

29112985
// Message handlers:
@@ -3563,6 +3637,20 @@ impl<SP: Deref> Channel<SP> where
35633637
}
35643638
}
35653639
},
3640+
&HTLCUpdateAwaitingACK::FailMalformedHTLC { htlc_id, failure_code, sha256_of_onion } => {
3641+
match self.fail_htlc(htlc_id, (failure_code, sha256_of_onion), false, logger) {
3642+
Ok(update_fail_malformed_opt) => {
3643+
debug_assert!(update_fail_malformed_opt.is_some()); // See above comment
3644+
update_fail_count += 1;
3645+
},
3646+
Err(e) => {
3647+
if let ChannelError::Ignore(_) = e {}
3648+
else {
3649+
panic!("Got a non-IgnoreError action trying to fail holding cell HTLC");
3650+
}
3651+
}
3652+
}
3653+
},
35663654
}
35673655
}
35683656
if update_add_count == 0 && update_fulfill_count == 0 && update_fail_count == 0 && self.context.holding_cell_update_fee.is_none() {
@@ -7433,6 +7521,8 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
74337521

74347522
let mut holding_cell_skimmed_fees: Vec<Option<u64>> = Vec::new();
74357523
let mut holding_cell_blinding_points: Vec<Option<PublicKey>> = Vec::new();
7524+
// Vec of (htlc_id, failure_code, sha256_of_onion)
7525+
let mut malformed_htlcs: Vec<(u64, u16, [u8; 32])> = Vec::new();
74367526
(self.context.holding_cell_htlc_updates.len() as u64).write(writer)?;
74377527
for update in self.context.holding_cell_htlc_updates.iter() {
74387528
match update {
@@ -7460,6 +7550,18 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
74607550
htlc_id.write(writer)?;
74617551
err_packet.write(writer)?;
74627552
}
7553+
&HTLCUpdateAwaitingACK::FailMalformedHTLC {
7554+
htlc_id, failure_code, sha256_of_onion
7555+
} => {
7556+
// We don't want to break downgrading by adding a new variant, so write a dummy
7557+
// `::FailHTLC` variant and write the real malformed error as an optional TLV.
7558+
malformed_htlcs.push((htlc_id, failure_code, sha256_of_onion));
7559+
7560+
let dummy_err_packet = msgs::OnionErrorPacket { data: Vec::new() };
7561+
2u8.write(writer)?;
7562+
htlc_id.write(writer)?;
7563+
dummy_err_packet.write(writer)?;
7564+
}
74637565
}
74647566
}
74657567

@@ -7620,6 +7722,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
76207722
(38, self.context.is_batch_funding, option),
76217723
(39, pending_outbound_blinding_points, optional_vec),
76227724
(41, holding_cell_blinding_points, optional_vec),
7725+
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
76237726
});
76247727

76257728
Ok(())
@@ -7910,6 +8013,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
79108013
let mut pending_outbound_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
79118014
let mut holding_cell_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
79128015

8016+
let mut malformed_htlcs: Option<Vec<(u64, u16, [u8; 32])>> = None;
8017+
79138018
read_tlv_fields!(reader, {
79148019
(0, announcement_sigs, option),
79158020
(1, minimum_depth, option),
@@ -7938,6 +8043,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
79388043
(38, is_batch_funding, option),
79398044
(39, pending_outbound_blinding_points_opt, optional_vec),
79408045
(41, holding_cell_blinding_points_opt, optional_vec),
8046+
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
79418047
});
79428048

79438049
let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -8032,6 +8138,22 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
80328138
if iter.next().is_some() { return Err(DecodeError::InvalidValue) }
80338139
}
80348140

8141+
if let Some(malformed_htlcs) = malformed_htlcs {
8142+
for (malformed_htlc_id, failure_code, sha256_of_onion) in malformed_htlcs {
8143+
let htlc_idx = holding_cell_htlc_updates.iter().position(|htlc| {
8144+
if let HTLCUpdateAwaitingACK::FailHTLC { htlc_id, err_packet } = htlc {
8145+
let matches = *htlc_id == malformed_htlc_id;
8146+
if matches { debug_assert!(err_packet.data.is_empty()) }
8147+
matches
8148+
} else { false }
8149+
}).ok_or(DecodeError::InvalidValue)?;
8150+
let malformed_htlc = HTLCUpdateAwaitingACK::FailMalformedHTLC {
8151+
htlc_id: malformed_htlc_id, failure_code, sha256_of_onion
8152+
};
8153+
let _ = core::mem::replace(&mut holding_cell_htlc_updates[htlc_idx], malformed_htlc);
8154+
}
8155+
}
8156+
80358157
Ok(Channel {
80368158
context: ChannelContext {
80378159
user_id,
@@ -8166,6 +8288,7 @@ mod tests {
81668288
use bitcoin::blockdata::transaction::{Transaction, TxOut};
81678289
use bitcoin::blockdata::opcodes;
81688290
use bitcoin::network::constants::Network;
8291+
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
81698292
use crate::ln::{PaymentHash, PaymentPreimage};
81708293
use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint};
81718294
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
@@ -8702,8 +8825,9 @@ mod tests {
87028825
}
87038826

87048827
#[test]
8705-
fn blinding_point_skimmed_fee_ser() {
8706-
// Ensure that channel blinding points and skimmed fees are (de)serialized properly.
8828+
fn blinding_point_skimmed_fee_malformed_ser() {
8829+
// Ensure that channel blinding points, skimmed fees, and malformed HTLCs are (de)serialized
8830+
// properly.
87078831
let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000});
87088832
let secp_ctx = Secp256k1::new();
87098833
let seed = [42; 32];
@@ -8768,13 +8892,19 @@ mod tests {
87688892
payment_preimage: PaymentPreimage([42; 32]),
87698893
htlc_id: 0,
87708894
};
8771-
let mut holding_cell_htlc_updates = Vec::with_capacity(10);
8772-
for i in 0..10 {
8773-
if i % 3 == 0 {
8895+
let dummy_holding_cell_failed_htlc = |htlc_id| HTLCUpdateAwaitingACK::FailHTLC {
8896+
htlc_id, err_packet: msgs::OnionErrorPacket { data: vec![42] }
8897+
};
8898+
let dummy_holding_cell_malformed_htlc = |htlc_id| HTLCUpdateAwaitingACK::FailMalformedHTLC {
8899+
htlc_id, failure_code: INVALID_ONION_BLINDING, sha256_of_onion: [0; 32],
8900+
};
8901+
let mut holding_cell_htlc_updates = Vec::with_capacity(12);
8902+
for i in 0..12 {
8903+
if i % 5 == 0 {
87748904
holding_cell_htlc_updates.push(dummy_holding_cell_add_htlc.clone());
8775-
} else if i % 3 == 1 {
8905+
} else if i % 5 == 1 {
87768906
holding_cell_htlc_updates.push(dummy_holding_cell_claim_htlc.clone());
8777-
} else {
8907+
} else if i % 5 == 2 {
87788908
let mut dummy_add = dummy_holding_cell_add_htlc.clone();
87798909
if let HTLCUpdateAwaitingACK::AddHTLC {
87808910
ref mut blinding_point, ref mut skimmed_fee_msat, ..
@@ -8783,6 +8913,10 @@ mod tests {
87838913
*skimmed_fee_msat = Some(42);
87848914
} else { panic!() }
87858915
holding_cell_htlc_updates.push(dummy_add);
8916+
} else if i % 5 == 3 {
8917+
holding_cell_htlc_updates.push(dummy_holding_cell_malformed_htlc(i as u64));
8918+
} else {
8919+
holding_cell_htlc_updates.push(dummy_holding_cell_failed_htlc(i as u64));
87868920
}
87878921
}
87888922
chan.context.holding_cell_htlc_updates = holding_cell_htlc_updates.clone();

0 commit comments

Comments
 (0)