|
| 1 | +// This file is Copyright its original authors, visible in version control |
| 2 | +// history. |
| 3 | +// |
| 4 | +// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE |
| 5 | +// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 6 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. |
| 7 | +// You may not use this file except in accordance with one or both of these |
| 8 | +// licenses. |
| 9 | + |
| 10 | +//! Tests for calculating the maximum length of a path based on the payment metadata, custom TLVs, |
| 11 | +//! and/or blinded paths present. |
| 12 | +
|
| 13 | +use bitcoin::secp256k1::Secp256k1; |
| 14 | +use crate::blinded_path::BlindedPath; |
| 15 | +use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs}; |
| 16 | +use crate::events::MessageSendEventsProvider; |
| 17 | +use crate::ln::PaymentSecret; |
| 18 | +use crate::ln::blinded_payment_tests::get_blinded_route_parameters; |
| 19 | +use crate::ln::channelmanager::PaymentId; |
| 20 | +use crate::ln::functional_test_utils::*; |
| 21 | +use crate::ln::msgs; |
| 22 | +use crate::ln::onion_utils; |
| 23 | +use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure}; |
| 24 | +use crate::prelude::*; |
| 25 | +use crate::routing::router::{PaymentParameters, RouteParameters}; |
| 26 | +use crate::util::errors::APIError; |
| 27 | +use crate::util::ser::Writeable; |
| 28 | +use crate::util::test_utils; |
| 29 | + |
| 30 | +// 3+32 (payload length and HMAC) + 2+8 (amt_to_forward) + |
| 31 | +// 2+4 (outgoing_cltv_value) + 2+8 (short_channel_id) |
| 32 | +const INTERMED_PAYLOAD_LEN_ESTIMATE: usize = 61; |
| 33 | + |
| 34 | +// Length of the HMAC of an onion payload when encoded into the packet. |
| 35 | +const PAYLOAD_HMAC_LEN: usize = 32; |
| 36 | + |
| 37 | +#[test] |
| 38 | +fn large_payment_metadata() { |
| 39 | + // Test that we'll limit our maximum path length based on the size of the provided |
| 40 | + // payment_metadata, and refuse to send at all prior to pathfinding if it's too large. |
| 41 | + let chanmon_cfgs = create_chanmon_cfgs(3); |
| 42 | + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); |
| 43 | + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); |
| 44 | + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); |
| 45 | + create_announced_chan_between_nodes(&nodes, 0, 1); |
| 46 | + create_announced_chan_between_nodes(&nodes, 1, 2); |
| 47 | + |
| 48 | + let amt_msat = 100_000; |
| 49 | + |
| 50 | + // Construct payment_metadata such that we can send the payment to the next hop but no further |
| 51 | + // without exceeding the max onion packet size. |
| 52 | + let final_payload_len_without_metadata = msgs::OutboundOnionPayload::Receive { |
| 53 | + payment_data: Some(msgs::FinalOnionHopData { |
| 54 | + payment_secret: PaymentSecret([0; 32]), total_msat: amt_msat |
| 55 | + }), |
| 56 | + payment_metadata: None, |
| 57 | + keysend_preimage: None, |
| 58 | + custom_tlvs: &Vec::new(), |
| 59 | + sender_intended_htlc_amt_msat: amt_msat, |
| 60 | + cltv_expiry_height: nodes[0].best_block_info().1 + TEST_FINAL_CLTV, |
| 61 | + }.serialized_length(); |
| 62 | + let max_metadata_len = 1300 |
| 63 | + - 1 // metdata type |
| 64 | + - crate::util::ser::BigSize(1200).serialized_length() // metadata length |
| 65 | + - 2 // onion payload varint prefix increased ser size due to metadata |
| 66 | + - PAYLOAD_HMAC_LEN |
| 67 | + - final_payload_len_without_metadata; |
| 68 | + let mut payment_metadata = vec![42; max_metadata_len]; |
| 69 | + |
| 70 | + // Check that the maximum-size metadata is sendable. |
| 71 | + let (route_0_1, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat); |
| 72 | + let mut recipient_onion_max_md_size = RecipientOnionFields { |
| 73 | + payment_secret: Some(payment_secret), |
| 74 | + payment_metadata: Some(payment_metadata.clone()), |
| 75 | + custom_tlvs: Vec::new(), |
| 76 | + }; |
| 77 | + nodes[0].node.send_payment(payment_hash, recipient_onion_max_md_size.clone(), PaymentId(payment_hash.0), route_0_1.route_params.clone().unwrap(), Retry::Attempts(0)).unwrap(); |
| 78 | + check_added_monitors!(nodes[0], 1); |
| 79 | + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); |
| 80 | + assert_eq!(events.len(), 1); |
| 81 | + let path = &[&nodes[1]]; |
| 82 | + let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap()) |
| 83 | + .with_payment_secret(payment_secret) |
| 84 | + .with_payment_metadata(payment_metadata.clone()); |
| 85 | + do_pass_along_path(args); |
| 86 | + claim_payment_along_route(&nodes[0], &[&[&nodes[1]]], false, payment_preimage); |
| 87 | + |
| 88 | + // Check that the payment parameter for max path length will prevent us from routing past our |
| 89 | + // next-hop peer given the payment_metadata size. |
| 90 | + let (mut route_0_2, payment_hash_2, payment_preimage_2, payment_secret_2) = get_route_and_payment_hash!(&nodes[0], &nodes[2], amt_msat); |
| 91 | + let mut route_params_0_2 = route_0_2.route_params.clone().unwrap(); |
| 92 | + route_params_0_2.payment_params.max_intermediate_hops = 0; |
| 93 | + nodes[0].router.expect_find_route_query(route_params_0_2); |
| 94 | + let err = nodes[0].node.send_payment(payment_hash_2, recipient_onion_max_md_size.clone(), PaymentId(payment_hash_2.0), route_0_2.route_params.clone().unwrap(), Retry::Attempts(0)).unwrap_err(); |
| 95 | + assert_eq!(err, RetryableSendFailure::RouteNotFound); |
| 96 | + |
| 97 | + // If our payment_metadata contains 1 additional byte, we'll fail prior to pathfinding. |
| 98 | + let mut recipient_onion_too_large_md = recipient_onion_max_md_size.clone(); |
| 99 | + recipient_onion_too_large_md.payment_metadata.as_mut().map(|mut md| md.push(42)); |
| 100 | + let err = nodes[0].node.send_payment(payment_hash, recipient_onion_too_large_md.clone(), PaymentId(payment_hash.0), route_0_1.route_params.clone().unwrap(), Retry::Attempts(0)).unwrap_err(); |
| 101 | + assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded); |
| 102 | + |
| 103 | + // Confirm that we'll fail to construct an onion packet given this payment_metadata that's too |
| 104 | + // large for even a 1-hop path. |
| 105 | + let secp_ctx = Secp256k1::signing_only(); |
| 106 | + let err = onion_utils::create_payment_onion(&secp_ctx, &route_0_1.paths[0], &test_utils::privkey(42), amt_msat, &recipient_onion_too_large_md, nodes[0].best_block_info().1, &payment_hash, &None, [0; 32]).unwrap_err(); |
| 107 | + match err { |
| 108 | + APIError::InvalidRoute { err } => { |
| 109 | + assert_eq!(err, "Route size too large considering onion data"); |
| 110 | + }, |
| 111 | + _ => panic!(), |
| 112 | + } |
| 113 | + |
| 114 | + // If we remove enough payment_metadata bytes to allow for 1 intermediate hop, we're now able to |
| 115 | + // send to nodes[2]. |
| 116 | + let mut recipient_onion_allws_2_hops = RecipientOnionFields { |
| 117 | + payment_secret: Some(payment_secret_2), |
| 118 | + payment_metadata: Some(vec![42; max_metadata_len - INTERMED_PAYLOAD_LEN_ESTIMATE]), |
| 119 | + custom_tlvs: Vec::new(), |
| 120 | + }; |
| 121 | + let mut route_params_0_2 = route_0_2.route_params.clone().unwrap(); |
| 122 | + route_params_0_2.payment_params.max_intermediate_hops = 1; |
| 123 | + nodes[0].router.expect_find_route_query(route_params_0_2); |
| 124 | + nodes[0].node.send_payment(payment_hash_2, recipient_onion_allws_2_hops.clone(), PaymentId(payment_hash_2.0), route_0_2.route_params.unwrap(), Retry::Attempts(0)).unwrap(); |
| 125 | + check_added_monitors!(nodes[0], 1); |
| 126 | + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); |
| 127 | + assert_eq!(events.len(), 1); |
| 128 | + let path = &[&nodes[1], &nodes[2]]; |
| 129 | + let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash_2, events.pop().unwrap()) |
| 130 | + .with_payment_secret(payment_secret_2) |
| 131 | + .with_payment_metadata(recipient_onion_allws_2_hops.payment_metadata.unwrap()); |
| 132 | + do_pass_along_path(args); |
| 133 | + claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage_2); |
| 134 | +} |
| 135 | + |
| 136 | +#[test] |
| 137 | +fn one_hop_blinded_path_with_custom_tlv() { |
| 138 | + // Test that we'll limit our maximum path length when paying to a 1-hop blinded path based on the |
| 139 | + // size of the provided custom TLV, and refuse to send at all prior to pathfinding if it's too |
| 140 | + // large. |
| 141 | + let chanmon_cfgs = create_chanmon_cfgs(3); |
| 142 | + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); |
| 143 | + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); |
| 144 | + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); |
| 145 | + create_announced_chan_between_nodes(&nodes, 0, 1); |
| 146 | + let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents; |
| 147 | + |
| 148 | + // Construct the route parameters for sending to nodes[2]'s 1-hop blinded path. |
| 149 | + let amt_msat = 100_000; |
| 150 | + let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None); |
| 151 | + let payee_tlvs = ReceiveTlvs { |
| 152 | + payment_secret, |
| 153 | + payment_constraints: PaymentConstraints { |
| 154 | + max_cltv_expiry: u32::max_value(), |
| 155 | + htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat, |
| 156 | + }, |
| 157 | + payment_context: PaymentContext::unknown(), |
| 158 | + }; |
| 159 | + let mut secp_ctx = Secp256k1::new(); |
| 160 | + let blinded_path = BlindedPath::one_hop_for_payment( |
| 161 | + nodes[2].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16, |
| 162 | + &chanmon_cfgs[2].keys_manager, &secp_ctx |
| 163 | + ).unwrap(); |
| 164 | + let route_params = RouteParameters::from_payment_params_and_value( |
| 165 | + PaymentParameters::blinded(vec![blinded_path.clone()]), |
| 166 | + amt_msat, |
| 167 | + ); |
| 168 | + |
| 169 | + // Calculate the maximum custom TLV value size where a valid onion packet is still possible. |
| 170 | + const CUSTOM_TLV_TYPE: u64 = 65537; |
| 171 | + let final_payload_len_without_custom_tlv = msgs::OutboundOnionPayload::BlindedReceive { |
| 172 | + sender_intended_htlc_amt_msat: amt_msat, |
| 173 | + total_msat: amt_msat, |
| 174 | + cltv_expiry_height: nodes[0].best_block_info().1 + TEST_FINAL_CLTV, |
| 175 | + encrypted_tlvs: &blinded_path.1.blinded_hops[0].encrypted_payload, |
| 176 | + intro_node_blinding_point: Some(blinded_path.1.blinding_point), |
| 177 | + keysend_preimage: None, |
| 178 | + custom_tlvs: &Vec::new() |
| 179 | + }.serialized_length(); |
| 180 | + let max_custom_tlv_len = 1300 |
| 181 | + - crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() // custom TLV type |
| 182 | + - crate::util::ser::BigSize(1200).serialized_length() // custom TLV length |
| 183 | + - 2 // onion payload varint prefix increased ser size due to custom TLV |
| 184 | + - 1 // ?? why is this needed |
| 185 | + - PAYLOAD_HMAC_LEN |
| 186 | + - final_payload_len_without_custom_tlv; |
| 187 | + |
| 188 | + // Check that we can send the maximum custom TLV with 0 unblinded intermediate hops. |
| 189 | + let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty() |
| 190 | + .with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) |
| 191 | + .unwrap(); |
| 192 | + nodes[1].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); |
| 193 | + check_added_monitors(&nodes[1], 1); |
| 194 | + |
| 195 | + let mut events = nodes[1].node.get_and_clear_pending_msg_events(); |
| 196 | + assert_eq!(events.len(), 1); |
| 197 | + let path = &[&nodes[2]]; |
| 198 | + let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap()) |
| 199 | + .with_payment_secret(payment_secret) |
| 200 | + .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()); |
| 201 | + do_pass_along_path(args); |
| 202 | + claim_payment_along_route(&nodes[1], &[&[&nodes[2]]], false, payment_preimage); |
| 203 | + |
| 204 | + // If 1 byte is added to the custom TLV value, we'll fail to send prior to pathfinding. |
| 205 | + let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone(); |
| 206 | + recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42); |
| 207 | + let err = nodes[1].node.send_payment(payment_hash, recipient_onion_too_large_custom_tlv, PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); |
| 208 | + assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded); |
| 209 | + |
| 210 | + // With the maximum-size custom TLV, our max path length is limited to 1, so attempting to route |
| 211 | + // nodes[0] -> nodes[2] will fail. |
| 212 | + let err = nodes[0].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); |
| 213 | + assert_eq!(err, RetryableSendFailure::RouteNotFound); |
| 214 | + |
| 215 | + // If we remove enough custom TLV bytes to allow for 1 intermediate hop, we're now able to send |
| 216 | + // nodes[0] -> nodes[2]. |
| 217 | + let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone(); |
| 218 | + recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); |
| 219 | + nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); |
| 220 | + check_added_monitors(&nodes[0], 1); |
| 221 | + |
| 222 | + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); |
| 223 | + assert_eq!(events.len(), 1); |
| 224 | + let path = &[&nodes[1], &nodes[2]]; |
| 225 | + let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap()) |
| 226 | + .with_payment_secret(payment_secret) |
| 227 | + .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs); |
| 228 | + do_pass_along_path(args); |
| 229 | + claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage); |
| 230 | +} |
| 231 | + |
| 232 | +#[test] |
| 233 | +fn blinded_path_with_custom_tlv() { |
| 234 | + // Test that we'll limit our maximum path length when paying to a blinded path based on the size |
| 235 | + // of the provided custom TLV, and refuse to send at all prior to pathfinding if it's too large. |
| 236 | + let chanmon_cfgs = create_chanmon_cfgs(4); |
| 237 | + let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); |
| 238 | + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); |
| 239 | + let nodes = create_network(4, &node_cfgs, &node_chanmgrs); |
| 240 | + create_announced_chan_between_nodes(&nodes, 0, 1); |
| 241 | + create_announced_chan_between_nodes(&nodes, 1, 2); |
| 242 | + let chan_upd_2_3 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).0.contents; |
| 243 | + |
| 244 | + // Construct the route parameters for sending to nodes[3]'s blinded path. |
| 245 | + let amt_msat = 100_000; |
| 246 | + let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None); |
| 247 | + let route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000, |
| 248 | + nodes.iter().skip(2).map(|n| n.node.get_our_node_id()).collect(), &[&chan_upd_2_3], |
| 249 | + &chanmon_cfgs[3].keys_manager); |
| 250 | + |
| 251 | + // Calculate the maximum custom TLV value size where a valid onion packet is still possible. |
| 252 | + const CUSTOM_TLV_TYPE: u64 = 65537; |
| 253 | + let mut route = get_route(&nodes[1], &route_params).unwrap(); |
| 254 | + let reserved_packet_bytes_without_custom_tlv: usize = onion_utils::build_onion_payloads( |
| 255 | + &route.paths[0], amt_msat, &RecipientOnionFields::spontaneous_empty(), |
| 256 | + nodes[0].best_block_info().1, &None |
| 257 | + ) |
| 258 | + .unwrap() |
| 259 | + .0 |
| 260 | + .iter() |
| 261 | + .map(|payload| payload.serialized_length() + PAYLOAD_HMAC_LEN) |
| 262 | + .sum(); |
| 263 | + let max_custom_tlv_len = 1300 |
| 264 | + - crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() // custom TLV type |
| 265 | + - crate::util::ser::BigSize(1200).serialized_length() // custom TLV length |
| 266 | + - 2 // onion payload varint prefix increased ser size due to custom TLV |
| 267 | + - 1 // ?? why is this needed |
| 268 | + - reserved_packet_bytes_without_custom_tlv; |
| 269 | + |
| 270 | + // Check that we can send the maximum custom TLV size with 0 intermediate unblinded hops. |
| 271 | + let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty() |
| 272 | + .with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) |
| 273 | + .unwrap(); |
| 274 | + nodes[1].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); |
| 275 | + check_added_monitors(&nodes[1], 1); |
| 276 | + |
| 277 | + let mut events = nodes[1].node.get_and_clear_pending_msg_events(); |
| 278 | + assert_eq!(events.len(), 1); |
| 279 | + let path = &[&nodes[2], &nodes[3]]; |
| 280 | + let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap()) |
| 281 | + .with_payment_secret(payment_secret) |
| 282 | + .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()); |
| 283 | + do_pass_along_path(args); |
| 284 | + claim_payment_along_route(&nodes[1], &[&[&nodes[2], &nodes[3]]], false, payment_preimage); |
| 285 | + |
| 286 | + // If 1 byte is added to the custom TLV value, we'll fail to send prior to pathfinding. |
| 287 | + let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone(); |
| 288 | + recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42); |
| 289 | + let err = nodes[1].node.send_payment(payment_hash, recipient_onion_too_large_custom_tlv, PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); |
| 290 | + assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded); |
| 291 | + |
| 292 | + // With the maximum-size custom TLV, we can't have any intermediate unblinded hops, so attempting |
| 293 | + // to route nodes[0] -> nodes[3] will fail. |
| 294 | + let err = nodes[0].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); |
| 295 | + assert_eq!(err, RetryableSendFailure::RouteNotFound); |
| 296 | + |
| 297 | + // If we remove enough custom TLV bytes to allow for 1 intermediate hop, we're now able to send |
| 298 | + // nodes[0] -> nodes[3]. |
| 299 | + let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone(); |
| 300 | + recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); |
| 301 | + nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); |
| 302 | + check_added_monitors(&nodes[0], 1); |
| 303 | + |
| 304 | + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); |
| 305 | + assert_eq!(events.len(), 1); |
| 306 | + let path = &[&nodes[1], &nodes[2], &nodes[3]]; |
| 307 | + let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap()) |
| 308 | + .with_payment_secret(payment_secret) |
| 309 | + .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs); |
| 310 | + do_pass_along_path(args); |
| 311 | + claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2], &nodes[3]]], false, payment_preimage); |
| 312 | +} |
0 commit comments