Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sending custom TLVs to to blinded recipients #2975

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1264,3 +1264,50 @@ fn blinded_mpp_keysend() {
Some(payment_secret), ev.clone(), true, Some(keysend_preimage));
claim_payment_along_route(&nodes[0], expected_route, false, keysend_preimage);
}

#[test]
fn custom_tlvs_to_blinded_path() {
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::one_hop_for_payment(
nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();

let route_params = RouteParameters::from_payment_params_and_value(
PaymentParameters::blinded(vec![blinded_path]),
amt_msat,
);

let recipient_onion_fields = RecipientOnionFields::spontaneous_empty()
.with_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])])
arik-so marked this conversation as resolved.
Show resolved Hide resolved
.unwrap();
nodes[0].node.send_payment(payment_hash, recipient_onion_fields.clone(),
PaymentId(payment_hash.0), route_params, 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 ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);

let path = &[&nodes[1]];
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, ev)
.with_payment_secret(payment_secret)
.with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone());
do_pass_along_path(args);
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
}
10 changes: 8 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2512,6 +2512,7 @@ pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
pub custom_tlvs: Vec<(u64, Vec<u8>)>,
}

impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
Expand All @@ -2522,7 +2523,7 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
Self {
origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event,
payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None,
is_probe: false,
is_probe: false, custom_tlvs: Vec::new(),
}
}
pub fn without_clearing_recipient_events(mut self) -> Self {
Expand All @@ -2546,13 +2547,17 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
self.expected_preimage = Some(payment_preimage);
self
}
pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
self.custom_tlvs = custom_tlvs;
self
}
}

pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event> {
let PassAlongPathArgs {
origin_node, expected_path, recv_value, payment_hash: our_payment_hash,
payment_secret: our_payment_secret, event: ev, payment_claimable_expected,
clear_recipient_events, expected_preimage, is_probe
clear_recipient_events, expected_preimage, is_probe, custom_tlvs
} = args;

let mut payment_event = SendEvent::from_event(ev);
Expand Down Expand Up @@ -2585,6 +2590,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event>
assert_eq!(our_payment_hash, *payment_hash);
assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap());
assert!(onion_fields.is_some());
assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs);
match &purpose {
PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
assert_eq!(expected_preimage, *payment_preimage);
Expand Down
16 changes: 12 additions & 4 deletions lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,7 @@ mod fuzzy_internal_msgs {
payment_constraints: PaymentConstraints,
intro_node_blinding_point: Option<PublicKey>,
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
}
}

Expand Down Expand Up @@ -1737,6 +1738,7 @@ mod fuzzy_internal_msgs {
encrypted_tlvs: Vec<u8>,
intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
}
}

Expand Down Expand Up @@ -2581,16 +2583,21 @@ impl Writeable for OutboundOnionPayload {
},
Self::BlindedReceive {
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs,
intro_node_blinding_point, keysend_preimage,
intro_node_blinding_point, keysend_preimage, ref custom_tlvs,
} => {
// We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
// to reject any reserved types in the experimental range if new ones are ever
// standardized.
let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),
(4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
(10, *encrypted_tlvs, required_vec),
(12, intro_node_blinding_point, option),
(18, HighZeroBytesDroppedBigSize(*total_msat), required),
(5482373484, keysend_preimage, option)
});
(18, HighZeroBytesDroppedBigSize(*total_msat), required)
}, custom_tlvs.iter());
},
}
Ok(())
Expand Down Expand Up @@ -2677,6 +2684,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
payment_constraints,
intro_node_blinding_point,
keysend_preimage,
custom_tlvs,
})
},
}
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ pub(super) fn create_recv_pending_htlc_info(
cltv_expiry_height, payment_metadata, false),
msgs::InboundOnionPayload::BlindedReceive {
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
intro_node_blinding_point, payment_constraints, keysend_preimage, ..
intro_node_blinding_point, payment_constraints, keysend_preimage, custom_tlvs
} => {
check_blinded_payment_constraints(
sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
Expand All @@ -152,7 +152,7 @@ pub(super) fn create_recv_pending_htlc_info(
}
})?;
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
(Some(payment_data), keysend_preimage, Vec::new(),
(Some(payment_data), keysend_preimage, custom_tlvs,
sender_intended_htlc_amt_msat, cltv_expiry_height, None,
intro_node_blinding_point.is_none())
}
Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/onion_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ pub(super) fn build_onion_payloads(
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
intro_node_blinding_point: blinding_point.take(),
keysend_preimage: *keysend_preimage,
custom_tlvs: recipient_onion.custom_tlvs.clone(),
});
} else {
res.push(msgs::OutboundOnionPayload::BlindedForward {
Expand Down
13 changes: 5 additions & 8 deletions lightning/src/ln/payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3813,14 +3813,11 @@ fn test_retry_custom_tlvs() {
check_added_monitors!(nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let payment_claimable = pass_along_path(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000,
payment_hash, Some(payment_secret), events.pop().unwrap(), true, None).unwrap();
match payment_claimable {
Event::PaymentClaimable { onion_fields, .. } => {
assert_eq!(&onion_fields.unwrap().custom_tlvs()[..], &custom_tlvs[..]);
},
_ => panic!("Unexpected event"),
};
let path = &[&nodes[1], &nodes[2]];
let args = PassAlongPathArgs::new(&nodes[0], path, 1_000_000, payment_hash, events.pop().unwrap())
.with_payment_secret(payment_secret)
.with_custom_tlvs(custom_tlvs);
do_pass_along_path(args);
claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage);
}

Expand Down
Loading