Skip to content

Commit a41d75f

Browse files
committed
Add some tests of payment metadata being sent and received
1 parent e1e7903 commit a41d75f

File tree

4 files changed

+215
-0
lines changed

4 files changed

+215
-0
lines changed

lightning-invoice/src/payment.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ mod tests {
215215
use super::*;
216216
use crate::{InvoiceBuilder, Currency};
217217
use bitcoin_hashes::sha256::Hash as Sha256;
218+
use lightning::events::Event;
219+
use lightning::ln::msgs::ChannelMessageHandler;
218220
use lightning::ln::{PaymentPreimage, PaymentSecret};
219221
use lightning::ln::functional_test_utils::*;
220222
use secp256k1::{SecretKey, Secp256k1};
@@ -352,4 +354,52 @@ mod tests {
352354
_ => panic!()
353355
}
354356
}
357+
358+
#[test]
359+
#[cfg(feature = "std")]
360+
fn payment_metadata_end_to_end() {
361+
// Test that a payment metadata read from an invoice passed to `pay_invoice` makes it all
362+
// the way out through the `PaymentClaimable` event.
363+
let chanmon_cfgs = create_chanmon_cfgs(2);
364+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
365+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
366+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
367+
create_announced_chan_between_nodes(&nodes, 0, 1);
368+
369+
let payment_metadata = vec![42, 43, 44, 45, 46, 47, 48, 49, 42];
370+
371+
let (payment_hash, payment_secret) =
372+
nodes[1].node.create_inbound_payment(None, 7200, None).unwrap();
373+
374+
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
375+
.description("test".into())
376+
.payment_hash(Sha256::from_slice(&payment_hash.0).unwrap())
377+
.payment_secret(payment_secret)
378+
.current_timestamp()
379+
.min_final_cltv_expiry_delta(144)
380+
.amount_milli_satoshis(50_000)
381+
.payment_metadata(payment_metadata.clone())
382+
.build_signed(|hash| {
383+
Secp256k1::new().sign_ecdsa_recoverable(hash,
384+
&nodes[1].keys_manager.backing.get_node_secret_key())
385+
})
386+
.unwrap();
387+
388+
pay_invoice(&invoice, Retry::Attempts(0), nodes[0].node).unwrap();
389+
check_added_monitors(&nodes[0], 1);
390+
let send_event = SendEvent::from_node(&nodes[0]);
391+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
392+
commitment_signed_dance!(nodes[1], nodes[0], &send_event.commitment_msg, false);
393+
394+
expect_pending_htlcs_forwardable!(nodes[1]);
395+
396+
let mut events = nodes[1].node.get_and_clear_pending_events();
397+
assert_eq!(events.len(), 1);
398+
match events.pop().unwrap() {
399+
Event::PaymentClaimable { onion_fields, .. } => {
400+
assert_eq!(Some(payment_metadata), onion_fields.unwrap().payment_metadata);
401+
},
402+
_ => panic!("Unexpected event")
403+
}
404+
}
355405
}

lightning/src/ln/channelmanager.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,6 +2702,11 @@ where
27022702
self.pending_outbound_payments.test_add_new_pending_payment(payment_hash, recipient_onion, payment_id, route, None, &self.entropy_source, best_block_height)
27032703
}
27042704

2705+
#[cfg(test)]
2706+
pub(crate) fn test_set_payment_metadata(&self, payment_id: PaymentId, new_payment_metadata: Option<Vec<u8>>) {
2707+
self.pending_outbound_payments.test_set_payment_metadata(payment_id, new_payment_metadata);
2708+
}
2709+
27052710

27062711
/// Signals that no further retries for the given payment should occur. Useful if you have a
27072712
/// pending outbound payment with retries remaining, but wish to stop retrying the payment before

lightning/src/ln/outbound_payment.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,18 @@ impl OutboundPayments {
915915
}
916916
}
917917

918+
#[cfg(test)]
919+
pub(super) fn test_set_payment_metadata(
920+
&self, payment_id: PaymentId, new_payment_metadata: Option<Vec<u8>>
921+
) {
922+
match self.pending_outbound_payments.lock().unwrap().get_mut(&payment_id).unwrap() {
923+
PendingOutboundPayment::Retryable { payment_metadata, .. } => {
924+
*payment_metadata = new_payment_metadata;
925+
},
926+
_ => panic!("Need a retryable payment to update metadata on"),
927+
}
928+
}
929+
918930
#[cfg(test)]
919931
pub(super) fn test_add_new_pending_payment<ES: Deref>(
920932
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,

lightning/src/ln/payment_tests.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,3 +3013,151 @@ fn claim_from_closed_chan() {
30133013
do_claim_from_closed_chan(true);
30143014
do_claim_from_closed_chan(false);
30153015
}
3016+
3017+
fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) {
3018+
// Check that a payment metadata received on one HTLC that doesn't match the one received on
3019+
// another results in the HTLC being rejected.
3020+
//
3021+
// We first set up a diamond shaped network, allowing us to split a payment into two HTLCs, the
3022+
// first of which we'll deliver and the second of which we'll fail and then re-send with
3023+
// modified payment metadata, which will in turn result in it being failed by the recipient.
3024+
let chanmon_cfgs = create_chanmon_cfgs(4);
3025+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
3026+
let mut config = test_default_channel_config();
3027+
config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50;
3028+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, Some(config), Some(config), Some(config)]);
3029+
3030+
let persister;
3031+
let new_chain_monitor;
3032+
let nodes_0_deserialized;
3033+
3034+
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
3035+
3036+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
3037+
let chan_id_bd = create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 1_000_000, 0).2;
3038+
create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1_000_000, 0);
3039+
let chan_id_cd = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).2;
3040+
3041+
// Pay more than half of each channel's max, requiring MPP
3042+
let amt_msat = 750_000_000;
3043+
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[3], Some(amt_msat));
3044+
let payment_id = PaymentId(payment_hash.0);
3045+
let payment_metadata = vec![44, 49, 52, 142];
3046+
3047+
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id(), TEST_FINAL_CLTV)
3048+
.with_features(nodes[1].node.invoice_features());
3049+
let mut route_params = RouteParameters {
3050+
payment_params,
3051+
final_value_msat: amt_msat,
3052+
};
3053+
3054+
// Send the MPP payment, delivering the updated commitment state to nodes[1].
3055+
nodes[0].node.send_payment(payment_hash, RecipientOnionFields {
3056+
payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata),
3057+
}, payment_id, route_params.clone(), Retry::Attempts(1)).unwrap();
3058+
check_added_monitors!(nodes[0], 2);
3059+
3060+
let mut send_events = nodes[0].node.get_and_clear_pending_msg_events();
3061+
assert_eq!(send_events.len(), 2);
3062+
let first_send = SendEvent::from_event(send_events.pop().unwrap());
3063+
let second_send = SendEvent::from_event(send_events.pop().unwrap());
3064+
3065+
let (b_recv_ev, c_recv_ev) = if first_send.node_id == nodes[1].node.get_our_node_id() {
3066+
(&first_send, &second_send)
3067+
} else {
3068+
(&second_send, &first_send)
3069+
};
3070+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &b_recv_ev.msgs[0]);
3071+
commitment_signed_dance!(nodes[1], nodes[0], b_recv_ev.commitment_msg, false, true);
3072+
3073+
expect_pending_htlcs_forwardable!(nodes[1]);
3074+
check_added_monitors(&nodes[1], 1);
3075+
let b_forward_ev = SendEvent::from_node(&nodes[1]);
3076+
nodes[3].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &b_forward_ev.msgs[0]);
3077+
commitment_signed_dance!(nodes[3], nodes[1], b_forward_ev.commitment_msg, false, true);
3078+
3079+
expect_pending_htlcs_forwardable!(nodes[3]);
3080+
3081+
// Before delivering the second MPP HTLC to nodes[2], disconnect nodes[2] and nodes[3], which
3082+
// will result in nodes[2] failing the HTLC back.
3083+
nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id());
3084+
nodes[3].node.peer_disconnected(&nodes[2].node.get_our_node_id());
3085+
3086+
nodes[2].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &c_recv_ev.msgs[0]);
3087+
commitment_signed_dance!(nodes[2], nodes[0], c_recv_ev.commitment_msg, false, true);
3088+
3089+
let cs_fail = get_htlc_update_msgs(&nodes[2], &nodes[0].node.get_our_node_id());
3090+
nodes[0].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &cs_fail.update_fail_htlcs[0]);
3091+
commitment_signed_dance!(nodes[0], nodes[2], cs_fail.commitment_signed, false, true);
3092+
3093+
let payment_fail_retryable_evs = nodes[0].node.get_and_clear_pending_events();
3094+
assert_eq!(payment_fail_retryable_evs.len(), 2);
3095+
if let Event::PaymentPathFailed { .. } = payment_fail_retryable_evs[0] {} else { panic!(); }
3096+
if let Event::PendingHTLCsForwardable { .. } = payment_fail_retryable_evs[1] {} else { panic!(); }
3097+
3098+
// Before we allow the HTLC to be retried, optionally change the payment_metadata we have
3099+
// stored for our payment.
3100+
if do_modify {
3101+
nodes[0].node.test_set_payment_metadata(payment_id, Some(Vec::new()));
3102+
}
3103+
3104+
// Optionally reload nodes[3] to check that the payment_metadata is properly serialized with
3105+
// the payment state.
3106+
if do_reload {
3107+
let mon_bd = get_monitor!(nodes[3], chan_id_bd).encode();
3108+
let mon_cd = get_monitor!(nodes[3], chan_id_cd).encode();
3109+
reload_node!(nodes[3], config, &nodes[3].node.encode(), &[&mon_bd, &mon_cd],
3110+
persister, new_chain_monitor, nodes_0_deserialized);
3111+
nodes[1].node.peer_disconnected(&nodes[3].node.get_our_node_id());
3112+
reconnect_nodes(&nodes[1], &nodes[3], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
3113+
}
3114+
reconnect_nodes(&nodes[2], &nodes[3], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
3115+
3116+
// Create a new channel between C and D as A will refuse to retry on the existing one because
3117+
// it just failed.
3118+
let chan_id_cd_2 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).2;
3119+
3120+
// Now retry the failed HTLC.
3121+
nodes[0].node.process_pending_htlc_forwards();
3122+
check_added_monitors(&nodes[0], 1);
3123+
let as_resend = SendEvent::from_node(&nodes[0]);
3124+
nodes[2].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &as_resend.msgs[0]);
3125+
commitment_signed_dance!(nodes[2], nodes[0], as_resend.commitment_msg, false, true);
3126+
3127+
expect_pending_htlcs_forwardable!(nodes[2]);
3128+
check_added_monitors(&nodes[2], 1);
3129+
let cs_forward = SendEvent::from_node(&nodes[2]);
3130+
nodes[3].node.handle_update_add_htlc(&nodes[2].node.get_our_node_id(), &cs_forward.msgs[0]);
3131+
commitment_signed_dance!(nodes[3], nodes[2], cs_forward.commitment_msg, false, true);
3132+
3133+
// Finally, check that nodes[3] does the correct thing - either accepting the payment or, if
3134+
// the payment metadata was modified, failing only the one modified HTLC and retaining the
3135+
// other.
3136+
if do_modify {
3137+
expect_pending_htlcs_forwardable_ignore!(nodes[3]);
3138+
nodes[3].node.process_pending_htlc_forwards();
3139+
expect_pending_htlcs_forwardable_conditions(nodes[3].node.get_and_clear_pending_events(),
3140+
&[HTLCDestination::FailedPayment {payment_hash}]);
3141+
nodes[3].node.process_pending_htlc_forwards();
3142+
3143+
check_added_monitors(&nodes[3], 1);
3144+
let ds_fail = get_htlc_update_msgs(&nodes[3], &nodes[2].node.get_our_node_id());
3145+
3146+
nodes[2].node.handle_update_fail_htlc(&nodes[3].node.get_our_node_id(), &ds_fail.update_fail_htlcs[0]);
3147+
commitment_signed_dance!(nodes[2], nodes[3], ds_fail.commitment_signed, false, true);
3148+
expect_pending_htlcs_forwardable_conditions(nodes[2].node.get_and_clear_pending_events(),
3149+
&[HTLCDestination::NextHopChannel { node_id: Some(nodes[3].node.get_our_node_id()), channel_id: chan_id_cd_2 }]);
3150+
} else {
3151+
expect_pending_htlcs_forwardable!(nodes[3]);
3152+
expect_payment_claimable!(nodes[3], payment_hash, payment_secret, amt_msat);
3153+
claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], false, payment_preimage);
3154+
}
3155+
}
3156+
3157+
#[test]
3158+
fn test_payment_metadata_consistency() {
3159+
do_test_payment_metadata_consistency(true, true);
3160+
do_test_payment_metadata_consistency(true, false);
3161+
do_test_payment_metadata_consistency(false, true);
3162+
do_test_payment_metadata_consistency(false, false);
3163+
}

0 commit comments

Comments
 (0)