use bitcoin::secp256k1::{Secp256k1, PublicKey};
use crate::blinded_path::BlindedHop;
use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, Bolt12RefundContext, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs};
use crate::events::{Event, MessageSendEventsProvider};
use crate::types::payment::PaymentSecret;
use crate::ln::blinded_payment_tests::get_blinded_route_parameters;
use crate::ln::channelmanager::PaymentId;
use crate::types::features::BlindedHopFeatures;
use crate::ln::functional_test_utils::*;
use crate::ln::msgs;
use crate::ln::msgs::OnionMessageHandler;
use crate::ln::onion_utils;
use crate::ln::onion_utils::MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY;
use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure};
use crate::offers::nonce::Nonce;
use crate::prelude::*;
use crate::routing::router::{DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, PaymentParameters, RouteParameters};
use crate::sign::NodeSigner;
use crate::util::errors::APIError;
use crate::util::ser::Writeable;
use crate::util::test_utils;
const INTERMED_PAYLOAD_LEN_ESTIMATE: usize = 61;
const PAYLOAD_HMAC_LEN: usize = 32;
#[test]
fn large_payment_metadata() {
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes(&nodes, 0, 1);
create_announced_chan_between_nodes(&nodes, 1, 2);
let amt_msat = 100_000;
let final_payload_len_without_metadata = msgs::OutboundOnionPayload::Receive {
payment_data: Some(msgs::FinalOnionHopData {
payment_secret: PaymentSecret([0; 32]), total_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY
}),
payment_metadata: None,
keysend_preimage: None,
custom_tlvs: &Vec::new(),
sender_intended_htlc_amt_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
cltv_expiry_height: nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
}.serialized_length();
let max_metadata_len = 1300
- 1 - crate::util::ser::BigSize(1200).serialized_length() - 2 - PAYLOAD_HMAC_LEN
- final_payload_len_without_metadata;
let mut payment_metadata = vec![42; max_metadata_len];
let (mut route_0_1, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat);
let mut recipient_onion_max_md_size = RecipientOnionFields {
payment_secret: Some(payment_secret),
payment_metadata: Some(payment_metadata.clone()),
custom_tlvs: Vec::new(),
};
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();
check_added_monitors!(nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[1]];
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_payment_metadata(payment_metadata.clone());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], payment_preimage)
);
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);
let mut route_params_0_2 = route_0_2.route_params.clone().unwrap();
route_params_0_2.payment_params.max_path_length = 1;
nodes[0].router.expect_find_route_query(route_params_0_2);
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();
assert_eq!(err, RetryableSendFailure::RouteNotFound);
let mut recipient_onion_too_large_md = recipient_onion_max_md_size.clone();
recipient_onion_too_large_md.payment_metadata.as_mut().map(|mut md| md.push(42));
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();
assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded);
let secp_ctx = Secp256k1::signing_only();
route_0_1.paths[0].hops[0].fee_msat = MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY;
route_0_1.paths[0].hops[0].cltv_expiry_delta = DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA;
let err = onion_utils::create_payment_onion(&secp_ctx, &route_0_1.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_md, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, None, [0; 32]).unwrap_err();
match err {
APIError::InvalidRoute { err } => {
assert_eq!(err, "Route size too large considering onion data");
},
_ => panic!(),
}
let mut recipient_onion_allows_2_hops = RecipientOnionFields {
payment_secret: Some(payment_secret_2),
payment_metadata: Some(vec![42; max_metadata_len - INTERMED_PAYLOAD_LEN_ESTIMATE]),
custom_tlvs: Vec::new(),
};
let mut route_params_0_2 = route_0_2.route_params.clone().unwrap();
route_params_0_2.payment_params.max_path_length = 2;
nodes[0].router.expect_find_route_query(route_params_0_2);
nodes[0].node.send_payment(payment_hash_2, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash_2.0), route_0_2.route_params.unwrap(), Retry::Attempts(0)).unwrap();
check_added_monitors!(nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[1], &nodes[2]];
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash_2, events.pop().unwrap())
.with_payment_secret(payment_secret_2)
.with_payment_metadata(recipient_onion_allows_2_hops.payment_metadata.unwrap());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2]]], payment_preimage_2)
);
}
#[test]
fn one_hop_blinded_path_with_custom_tlv() {
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes(&nodes, 0, 1);
let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents;
let amt_msat = 100_000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat,
},
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = chanmon_cfgs[2].keys_manager.get_inbound_payment_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
&[], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[2].keys_manager, &secp_ctx
).unwrap();
let route_params = RouteParameters::from_payment_params_and_value(
PaymentParameters::blinded(vec![blinded_path.clone()]),
amt_msat,
);
const CUSTOM_TLV_TYPE: u64 = 65537;
let final_payload_len_without_custom_tlv = msgs::OutboundOnionPayload::BlindedReceive {
sender_intended_htlc_amt_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
total_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
cltv_expiry_height: nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
encrypted_tlvs: &blinded_path.blinded_hops()[0].encrypted_payload,
intro_node_blinding_point: Some(blinded_path.blinding_point()),
keysend_preimage: None,
invoice_request: None,
custom_tlvs: &Vec::new()
}.serialized_length();
let max_custom_tlv_len = 1300
- crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() - crate::util::ser::BigSize(1200).serialized_length() - 1 - PAYLOAD_HMAC_LEN
- final_payload_len_without_custom_tlv;
let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty()
.with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])])
.unwrap();
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();
check_added_monitors(&nodes[1], 1);
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[2]];
let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[1], &[&[&nodes[2]]], payment_preimage)
.with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone())
);
let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone();
recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42);
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();
assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded);
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();
assert_eq!(err, RetryableSendFailure::RouteNotFound);
let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone();
recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0);
nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap();
check_added_monitors(&nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[1], &nodes[2]];
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs.clone());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2]]], payment_preimage)
.with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs)
);
}
#[test]
fn blinded_path_with_custom_tlv() {
let chanmon_cfgs = create_chanmon_cfgs(4);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes(&nodes, 0, 1);
create_announced_chan_between_nodes(&nodes, 1, 2);
let chan_upd_2_3 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).0.contents;
let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
connect_blocks(&nodes[1], node_max_height - nodes[1].best_block_info().1);
connect_blocks(&nodes[2], node_max_height - nodes[2].best_block_info().1);
connect_blocks(&nodes[3], node_max_height - nodes[3].best_block_info().1);
let amt_msat = 100_000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
let route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000,
nodes.iter().skip(2).map(|n| n.node.get_our_node_id()).collect(), &[&chan_upd_2_3],
&chanmon_cfgs[3].keys_manager);
const CUSTOM_TLV_TYPE: u64 = 65537;
let mut route = get_route(&nodes[1], &route_params).unwrap();
let reserved_packet_bytes_without_custom_tlv: usize = onion_utils::build_onion_payloads(
&route.paths[0], MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
&RecipientOnionFields::spontaneous_empty(),
nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &None, None
)
.unwrap()
.0
.iter()
.map(|payload| payload.serialized_length() + PAYLOAD_HMAC_LEN)
.sum();
let max_custom_tlv_len = 1300
- crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() - crate::util::ser::BigSize(1200).serialized_length() - 2 - reserved_packet_bytes_without_custom_tlv;
let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty()
.with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])])
.unwrap();
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();
check_added_monitors(&nodes[1], 1);
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[2], &nodes[3]];
let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[1], &[&[&nodes[2], &nodes[3]]], payment_preimage)
.with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone())
);
let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone();
recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42);
let err = nodes[1].node.send_payment(payment_hash, recipient_onion_too_large_custom_tlv.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err();
assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded);
let secp_ctx = Secp256k1::signing_only();
route.paths[0].hops[0].fee_msat = MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY;
route.paths[0].hops[0].cltv_expiry_delta = DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA;
let err = onion_utils::create_payment_onion(&secp_ctx, &route.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_custom_tlv, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, None, [0; 32]).unwrap_err();
match err {
APIError::InvalidRoute { err } => {
assert_eq!(err, "Route size too large considering onion data");
},
_ => panic!(),
}
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();
assert_eq!(err, RetryableSendFailure::RouteNotFound);
let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone();
recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0);
nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap();
check_added_monitors(&nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let path = &[&nodes[1], &nodes[2], &nodes[3]];
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs.clone());
do_pass_along_path(args);
claim_payment_along_route(
ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2], &nodes[3]]], payment_preimage)
.with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs)
);
}
#[test]
fn bolt12_invoice_too_large_blinded_paths() {
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);
create_announced_chan_between_nodes(&nodes, 0, 1);
nodes[1].router.expect_blinded_payment_paths(vec![
BlindedPaymentPath::from_raw(
PublicKey::from_slice(&[2; 33]).unwrap(), PublicKey::from_slice(&[2; 33]).unwrap(),
vec![
BlindedHop {
blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(),
encrypted_payload: vec![42; 1300],
},
BlindedHop {
blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(),
encrypted_payload: vec![42; 1300],
},
],
BlindedPayInfo {
fee_base_msat: 42,
fee_proportional_millionths: 42,
cltv_expiry_delta: 42,
htlc_minimum_msat: 42,
htlc_maximum_msat: 42_000_000,
features: BlindedHopFeatures::empty(),
}
)
]);
let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), None).unwrap();
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap();
nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om);
let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(nodes[0].node.get_our_node_id()).unwrap();
nodes[0].onion_messenger.handle_onion_message(nodes[1].node.get_our_node_id(), &invoice_om);
nodes[0].logger.assert_log_contains("lightning::ln::channelmanager", "Failed paying invoice: OnionPacketSizeExceeded", 1);
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
Event::PaymentFailed { payment_id: id, .. } => {
assert_eq!(id, payment_id)
},
_ => panic!("Unexpected event"),
}
}