]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add blinded path {metadata} fields to Path, but disallow paying blinded paths for now
authorValentine Wallace <vwallace@protonmail.com>
Tue, 18 Apr 2023 16:06:35 +0000 (12:06 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Fri, 21 Apr 2023 19:35:04 +0000 (15:35 -0400)
12 files changed:
fuzz/src/chanmon_consistency.rs
lightning-background-processor/src/lib.rs
lightning/src/events/mod.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/payment_tests.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/util/macro_logger.rs

index 76305303a7883addb4593371b680b4052e7320cb..eca4c4c8e8e7fd864e8e142fb9be3000ffb5a21c 100644 (file)
@@ -359,7 +359,7 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p
                        channel_features: dest.channel_features(),
                        fee_msat: amt,
                        cltv_expiry_delta: 200,
-               }]}],
+               }], blinded_tail: None }],
                payment_params: None,
        }, payment_hash, RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_id)) {
                check_payment_err(err);
@@ -388,7 +388,7 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
                        channel_features: dest.channel_features(),
                        fee_msat: amt,
                        cltv_expiry_delta: 200,
-               }]}],
+               }], blinded_tail: None }],
                payment_params: None,
        }, payment_hash, RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_id)) {
                check_payment_err(err);
index 18ed6da06cd5e7e5d0574432693f732be28961e3..627f0db15aed1f2da21a9a0fe58ce91c94d65372 100644 (file)
@@ -1512,7 +1512,7 @@ mod tests {
                                channel_features: ChannelFeatures::empty(),
                                fee_msat: 0,
                                cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA as u32,
-                       }]};
+                       }], blinded_tail: None };
 
                        $nodes[0].scorer.lock().unwrap().expect(TestResult::PaymentFailure { path: path.clone(), short_channel_id: scored_scid });
                        $nodes[0].node.push_pending_event(Event::PaymentPathFailed {
index dc066b1e78e228eeb9766e647c0fd65241a37d5e..b5f682e1fb597eb0a923f214daace1ffba1e91a2 100644 (file)
@@ -1141,7 +1141,7 @@ impl MaybeReadable for Event {
                                                payment_hash,
                                                payment_failed_permanently,
                                                failure,
-                                               path: Path { hops: path.unwrap() },
+                                               path: Path { hops: path.unwrap(), blinded_tail: None },
                                                short_channel_id,
                                                #[cfg(test)]
                                                error_code,
@@ -1255,7 +1255,7 @@ impl MaybeReadable for Event {
                                        Ok(Some(Event::PaymentPathSuccessful {
                                                payment_id,
                                                payment_hash,
-                                               path: Path { hops: path.unwrap() },
+                                               path: Path { hops: path.unwrap(), blinded_tail: None },
                                        }))
                                };
                                f()
@@ -1316,7 +1316,7 @@ impl MaybeReadable for Event {
                                        Ok(Some(Event::ProbeSuccessful {
                                                payment_id,
                                                payment_hash,
-                                               path: Path { hops: path.unwrap() },
+                                               path: Path { hops: path.unwrap(), blinded_tail: None },
                                        }))
                                };
                                f()
@@ -1336,7 +1336,7 @@ impl MaybeReadable for Event {
                                        Ok(Some(Event::ProbeFailed {
                                                payment_id,
                                                payment_hash,
-                                               path: Path { hops: path.unwrap() },
+                                               path: Path { hops: path.unwrap(), blinded_tail: None },
                                                short_channel_id,
                                        }))
                                };
index 79711080c4b4929ca4fd17f5727f5f6748e35ef4..cc3f73523a379d17dd2a417567a90bfed70a0bde 100644 (file)
@@ -7202,7 +7202,7 @@ mod tests {
                        cltv_expiry: 200000000,
                        state: OutboundHTLCState::Committed,
                        source: HTLCSource::OutboundRoute {
-                               path: Path { hops: Vec::new() },
+                               path: Path { hops: Vec::new(), blinded_tail: None },
                                session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
                                first_hop_htlc_msat: 548,
                                payment_id: PaymentId([42; 32]),
index 5f77c43cc375d7ccc91fcbe787268462edd8483d..60de5a3d329f91e0e6748ee6cad6ea4dacb36e21 100644 (file)
@@ -7019,13 +7019,13 @@ impl Readable for HTLCSource {
                                        // instead.
                                        payment_id = Some(PaymentId(*session_priv.0.unwrap().as_ref()));
                                }
-                               let path = Path { hops: path_hops.ok_or(DecodeError::InvalidValue)? };
+                               let path = Path { hops: path_hops.ok_or(DecodeError::InvalidValue)?, blinded_tail: None };
                                if path.hops.len() == 0 {
                                        return Err(DecodeError::InvalidValue);
                                }
                                if let Some(params) = payment_params.as_mut() {
                                        if params.final_cltv_expiry_delta == 0 {
-                                               params.final_cltv_expiry_delta = path.final_cltv_expiry_delta();
+                                               params.final_cltv_expiry_delta = path.final_cltv_expiry_delta().ok_or(DecodeError::InvalidValue)?;
                                        }
                                }
                                Ok(HTLCSource::OutboundRoute {
index 65ad811d8583b2abbdbf10c647facba31ae6c633..d56f1bd3d376ac91ea84a92d60eb7dccee34efd3 100644 (file)
@@ -1044,7 +1044,7 @@ fn fake_network_test() {
        });
        hops[1].fee_msat = chan_4.1.contents.fee_base_msat as u64 + chan_4.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
        hops[0].fee_msat = chan_3.0.contents.fee_base_msat as u64 + chan_3.0.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
-       let payment_preimage_1 = send_along_route(&nodes[1], Route { paths: vec![Path { hops }], payment_params: None }, &vec!(&nodes[2], &nodes[3], &nodes[1])[..], 1000000).0;
+       let payment_preimage_1 = send_along_route(&nodes[1], Route { paths: vec![Path { hops, blinded_tail: None }], payment_params: None }, &vec!(&nodes[2], &nodes[3], &nodes[1])[..], 1000000).0;
 
        let mut hops = Vec::with_capacity(3);
        hops.push(RouteHop {
@@ -1073,7 +1073,7 @@ fn fake_network_test() {
        });
        hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
        hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
-       let payment_hash_2 = send_along_route(&nodes[1], Route { paths: vec![Path { hops }], payment_params: None }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).1;
+       let payment_hash_2 = send_along_route(&nodes[1], Route { paths: vec![Path { hops, blinded_tail: None }], payment_params: None }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).1;
 
        // Claim the rebalances...
        fail_payment(&nodes[1], &vec!(&nodes[3], &nodes[2], &nodes[1])[..], payment_hash_2);
index df0b903123d5d5a5b9fe9375f1450e1d7a16a28c..36abad71f2d5187be95638d53b9f70c7c9c925e0 100644 (file)
@@ -929,7 +929,7 @@ mod tests {
                                                channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
                                                short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // We fill in the payloads manually instead of generating them from RouteHops.
                                        },
-                       ]}],
+                       ], blinded_tail: None }],
                        payment_params: None,
                };
 
index 18763685f8f9ff58aa81b7927379578e71605802..636bc13a90b7adbe64facaadb253b7a4cfdf1c7e 100644 (file)
@@ -1000,6 +1000,10 @@ impl OutboundPayments {
                                path_errs.push(Err(APIError::InvalidRoute{err: "Path didn't go anywhere/had bogus size".to_owned()}));
                                continue 'path_check;
                        }
+                       if path.blinded_tail.is_some() {
+                               path_errs.push(Err(APIError::InvalidRoute{err: "Sending to blinded paths isn't supported yet".to_owned()}));
+                               continue 'path_check;
+                       }
                        for (idx, hop) in path.hops.iter().enumerate() {
                                if idx != path.hops.len() - 1 && hop.pubkey == our_node_id {
                                        path_errs.push(Err(APIError::InvalidRoute{err: "Path went through us but wasn't a simple rebalance loop to us".to_owned()}));
@@ -1552,7 +1556,7 @@ mod tests {
                                channel_features: ChannelFeatures::empty(),
                                fee_msat: 0,
                                cltv_expiry_delta: 0,
-                       }]}],
+                       }], blinded_tail: None }],
                        payment_params: Some(payment_params),
                };
                router.expect_find_route(route_params.clone(), Ok(route.clone()));
index b599bee342bae3e030faedb6b7f04b0383e57b1e..96de3e107803f14f0c0289331e00ae79ca639ea6 100644 (file)
@@ -1846,7 +1846,7 @@ fn auto_retry_partial_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: amt_msat / 2,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[1].node.get_our_node_id(),
                                node_features: nodes[1].node.node_features(),
@@ -1854,7 +1854,7 @@ fn auto_retry_partial_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: amt_msat / 2,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                ],
                payment_params: Some(route_params.payment_params.clone()),
        };
@@ -1867,7 +1867,7 @@ fn auto_retry_partial_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: amt_msat / 4,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[1].node.get_our_node_id(),
                                node_features: nodes[1].node.node_features(),
@@ -1875,7 +1875,7 @@ fn auto_retry_partial_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: amt_msat / 4,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                ],
                payment_params: Some(route_params.payment_params.clone()),
        };
@@ -1888,7 +1888,7 @@ fn auto_retry_partial_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: amt_msat / 4,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                ],
                payment_params: Some(route_params.payment_params.clone()),
        };
@@ -2135,7 +2135,7 @@ fn retry_multi_path_single_failed_payment() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: 10_000,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[1].node.get_our_node_id(),
                                node_features: nodes[1].node.node_features(),
@@ -2143,7 +2143,7 @@ fn retry_multi_path_single_failed_payment() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                ],
                payment_params: Some(payment_params),
        };
@@ -2229,7 +2229,7 @@ fn immediate_retry_on_failure() {
                                channel_features: nodes[1].node.channel_features(),
                                fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                ],
                payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
        };
@@ -2324,7 +2324,7 @@ fn no_extra_retries_on_back_to_back_fail() {
                                channel_features: nodes[2].node.channel_features(),
                                fee_msat: 100_000_000,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[1].node.get_our_node_id(),
                                node_features: nodes[1].node.node_features(),
@@ -2339,7 +2339,7 @@ fn no_extra_retries_on_back_to_back_fail() {
                                channel_features: nodes[2].node.channel_features(),
                                fee_msat: 100_000_000,
                                cltv_expiry_delta: 100,
-                       }]}
+                       }], blinded_tail: None }
                ],
                payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
        };
@@ -2526,7 +2526,7 @@ fn test_simple_partial_retry() {
                                channel_features: nodes[2].node.channel_features(),
                                fee_msat: 100_000_000,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[1].node.get_our_node_id(),
                                node_features: nodes[1].node.node_features(),
@@ -2541,7 +2541,7 @@ fn test_simple_partial_retry() {
                                channel_features: nodes[2].node.channel_features(),
                                fee_msat: 100_000_000,
                                cltv_expiry_delta: 100,
-                       }]}
+                       }], blinded_tail: None }
                ],
                payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
        };
@@ -2692,7 +2692,7 @@ fn test_threaded_payment_retries() {
                                channel_features: nodes[2].node.channel_features(),
                                fee_msat: amt_msat / 1000,
                                cltv_expiry_delta: 100,
-                       }]},
+                       }], blinded_tail: None },
                        Path { hops: vec![RouteHop {
                                pubkey: nodes[2].node.get_our_node_id(),
                                node_features: nodes[2].node.node_features(),
@@ -2707,7 +2707,7 @@ fn test_threaded_payment_retries() {
                                channel_features: nodes[3].node.channel_features(),
                                fee_msat: amt_msat - amt_msat / 1000,
                                cltv_expiry_delta: 100,
-                       }]}
+                       }], blinded_tail: None }
                ],
                payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
        };
index d4e7306c91c0c9ec2dd4a0c4360687901dcc6273..0a2cb9081f922ee84ef4d9cd29851191b3ae0c6f 100644 (file)
@@ -13,7 +13,7 @@ use bitcoin::secp256k1::PublicKey;
 use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
 
-use crate::blinded_path::BlindedPath;
+use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::ln::PaymentHash;
 use crate::ln::channelmanager::{ChannelDetails, PaymentId};
 use crate::ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
@@ -227,10 +227,18 @@ pub struct RouteHop {
        /// to reach this node.
        pub channel_features: ChannelFeatures,
        /// The fee taken on this hop (for paying for the use of the *next* channel in the path).
-       /// For the last hop, this should be the full value of this path's part of the payment.
+       /// If this is the last hop in [`Path::hops`]:
+       /// * if we're sending to a [`BlindedPath`], this is the fee paid for use of the entire blinded path
+       /// * otherwise, this is the full value of this [`Path`]'s part of the payment
+       ///
+       /// [`BlindedPath`]: crate::blinded_path::BlindedPath
        pub fee_msat: u64,
-       /// The CLTV delta added for this hop. For the last hop, this is the CLTV delta expected at the
-       /// destination.
+       /// The CLTV delta added for this hop.
+       /// If this is the last hop in [`Path::hops`]:
+       /// * if we're sending to a [`BlindedPath`], this is the CLTV delta for the entire blinded path
+       /// * otherwise, this is the CLTV delta expected at the destination
+       ///
+       /// [`BlindedPath`]: crate::blinded_path::BlindedPath
        pub cltv_expiry_delta: u32,
 }
 
@@ -243,30 +251,71 @@ impl_writeable_tlv_based!(RouteHop, {
        (10, cltv_expiry_delta, required),
 });
 
-/// A path in a [`Route`] to the payment recipient.
+/// The blinded portion of a [`Path`], if we're routing to a recipient who provided blinded paths in
+/// their BOLT12 [`Invoice`].
+///
+/// [`Invoice`]: crate::offers::invoice::Invoice
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct BlindedTail {
+       /// The hops of the [`BlindedPath`] provided by the recipient.
+       ///
+       /// [`BlindedPath`]: crate::blinded_path::BlindedPath
+       pub hops: Vec<BlindedHop>,
+       /// The blinding point of the [`BlindedPath`] provided by the recipient.
+       ///
+       /// [`BlindedPath`]: crate::blinded_path::BlindedPath
+       pub blinding_point: PublicKey,
+       /// Excess CLTV delta added to the recipient's CLTV expiry to deter intermediate nodes from
+       /// inferring the destination. May be 0.
+       pub excess_final_cltv_expiry_delta: u32,
+       /// The total amount paid on this [`Path`], excluding the fees.
+       pub final_value_msat: u64,
+}
+
+impl_writeable_tlv_based!(BlindedTail, {
+       (0, hops, vec_type),
+       (2, blinding_point, required),
+       (4, excess_final_cltv_expiry_delta, required),
+       (6, final_value_msat, required),
+});
+
+/// A path in a [`Route`] to the payment recipient. Must always be at least length one.
+/// If no [`Path::blinded_tail`] is present, then [`Path::hops`] length may be up to 19.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct Path {
-       /// The list of unblinded hops in this [`Path`].
+       /// The list of unblinded hops in this [`Path`]. Must be at least length one.
        pub hops: Vec<RouteHop>,
+       /// The blinded path at which this path terminates, if we're sending to one, and its metadata.
+       pub blinded_tail: Option<BlindedTail>,
 }
 
 impl Path {
        /// Gets the fees for a given path, excluding any excess paid to the recipient.
        pub fn fee_msat(&self) -> u64 {
-               // Do not count last hop of each path since that's the full value of the payment
-               self.hops.split_last().map(|(_, path_prefix)| path_prefix).unwrap_or(&[])
-                       .iter().map(|hop| &hop.fee_msat)
-                       .sum()
+               match &self.blinded_tail {
+                       Some(_) => self.hops.iter().map(|hop| hop.fee_msat).sum::<u64>(),
+                       None => {
+                               // Do not count last hop of each path since that's the full value of the payment
+                               self.hops.split_last().map_or(0,
+                                       |(_, path_prefix)| path_prefix.iter().map(|hop| hop.fee_msat).sum())
+                       }
+               }
        }
 
        /// Gets the total amount paid on this [`Path`], excluding the fees.
        pub fn final_value_msat(&self) -> u64 {
-               self.hops.last().map_or(0, |hop| hop.fee_msat)
+               match &self.blinded_tail {
+                       Some(blinded_tail) => blinded_tail.final_value_msat,
+                       None => self.hops.last().map_or(0, |hop| hop.fee_msat)
+               }
        }
 
        /// Gets the final hop's CLTV expiry delta.
-       pub fn final_cltv_expiry_delta(&self) -> u32 {
-               self.hops.last().map_or(0, |hop| hop.cltv_expiry_delta)
+       pub fn final_cltv_expiry_delta(&self) -> Option<u32> {
+               match &self.blinded_tail {
+                       Some(_) => None,
+                       None => self.hops.last().map(|hop| hop.cltv_expiry_delta)
+               }
        }
 }
 
@@ -274,11 +323,9 @@ impl Path {
 /// it can take multiple paths. Each path is composed of one or more hops through the network.
 #[derive(Clone, Hash, PartialEq, Eq)]
 pub struct Route {
-       /// The list of paths taken for a single (potentially-)multi-part payment. The pubkey of the
-       /// last [`RouteHop`] in each path must be the same. Each entry represents a list of hops, where
-       /// the last hop is the destination. Thus, this must always be at least length one. While the
-       /// maximum length of any given path is variable, keeping the length of any path less or equal to
-       /// 19 should currently ensure it is viable.
+       /// The list of [`Path`]s taken for a single (potentially-)multi-part payment. If no
+       /// [`BlindedTail`]s are present, then the pubkey of the last [`RouteHop`] in each path must be
+       /// the same.
        pub paths: Vec<Path>,
        /// The `payment_params` parameter passed to [`find_route`].
        /// This is used by `ChannelManager` to track information which may be required for retries,
@@ -340,7 +387,7 @@ impl Readable for Route {
                        if hops.is_empty() { return Err(DecodeError::InvalidValue); }
                        min_final_cltv_expiry_delta =
                                cmp::min(min_final_cltv_expiry_delta, hops.last().unwrap().cltv_expiry_delta);
-                       paths.push(Path { hops });
+                       paths.push(Path { hops, blinded_tail: None });
                }
                let mut payment_params = None;
                read_tlv_fields!(reader, {
@@ -2021,7 +2068,7 @@ where L::Target: Logger {
        for results_vec in selected_paths {
                let mut hops = Vec::with_capacity(results_vec.len());
                for res in results_vec { hops.push(res?); }
-               paths.push(Path { hops });
+               paths.push(Path { hops, blinded_tail: None });
        }
        let route = Route {
                paths,
@@ -5272,7 +5319,7 @@ mod tests {
                                        channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
                                        short_channel_id: 0, fee_msat: 225, cltv_expiry_delta: 0
                                },
-                       ]}],
+                       ], blinded_tail: None }],
                        payment_params: None,
                };
 
@@ -5294,7 +5341,7 @@ mod tests {
                                        channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
                                        short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0
                                },
-                       ]}, Path { hops: vec![
+                       ], blinded_tail: None }, Path { hops: vec![
                                RouteHop {
                                        pubkey: PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap(),
                                        channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
@@ -5305,7 +5352,7 @@ mod tests {
                                        channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
                                        short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0
                                },
-                       ]}],
+                       ], blinded_tail: None }],
                        payment_params: None,
                };
 
index 0756869c1a66dec3f17039049a9dbc9d39320534..6777ec8ea1bcae1d0c9b0edce074dd17969343d0 100644 (file)
@@ -1864,7 +1864,7 @@ mod tests {
                                path_hop(source_pubkey(), 41, 1),
                                path_hop(target_pubkey(), 42, 2),
                                path_hop(recipient_pubkey(), 43, amount_msat),
-                       ],
+                       ], blinded_tail: None,
                }
        }
 
@@ -2289,7 +2289,7 @@ mod tests {
                assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage), 128);
                assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage), 128);
 
-               scorer.payment_path_failed(&Path { hops: path }, 43);
+               scorer.payment_path_failed(&Path { hops: path, blinded_tail: None }, 43);
 
                assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage), 80);
                // Note that a default liquidity bound is used for B -> C as no channel exists
@@ -2823,7 +2823,7 @@ mod tests {
                        path_hop(source_pubkey(), 42, 1),
                        path_hop(sender_pubkey(), 41, 0),
                ];
-               scorer.payment_path_failed(&Path { hops: path }, 42);
+               scorer.payment_path_failed(&Path { hops: path, blinded_tail: None }, 42);
        }
 
        #[test]
index b7224be3ecea8cff537f3ea6373d71fd96716247..a9018f3da90c89f412a4bb55ca438c55f8abec77 100644 (file)
@@ -68,6 +68,7 @@ impl<'a> core::fmt::Display for DebugRoute<'a> {
                        for h in p.hops.iter() {
                                writeln!(f, " node_id: {}, short_channel_id: {}, fee_msat: {}, cltv_expiry_delta: {}", log_pubkey!(h.pubkey), h.short_channel_id, h.fee_msat, h.cltv_expiry_delta)?;
                        }
+                       writeln!(f, " blinded_tail: {:?}", p.blinded_tail)?;
                }
                Ok(())
        }