X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fpayment_tests.rs;h=cd75d48ebcbf29dbd758039b4448b2012696d28a;hb=3c525ef694130affba5b41ed7b91570b3d95c45e;hp=90c7ad7625ceb85dd4cbc318a755e5925ef55390;hpb=ae9e96e2772d2aaa3d6fbd1d17b83bb44f5ae07a;p=rust-lightning diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 90c7ad76..cd75d48e 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -18,7 +18,7 @@ use crate::chain::transaction::OutPoint; use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason}; use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS; use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo}; -use crate::ln::features::InvoiceFeatures; +use crate::ln::features::Bolt11InvoiceFeatures; use crate::ln::{msgs, PaymentSecret, PaymentPreimage}; use crate::ln::msgs::ChannelMessageHandler; use crate::ln::outbound_payment::Retry; @@ -490,7 +490,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) { // nodes[1] now immediately fails the HTLC as the next-hop channel is disconnected let _ = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); - reconnect_nodes(&nodes[1], &nodes[2], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + reconnect_nodes(ReconnectArgs::new(&nodes[1], &nodes[2])); let as_commitment_tx = get_local_commitment_txn!(nodes[0], chan_id)[0].clone(); if confirm_before_reload { @@ -789,7 +789,9 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) { nodes[0].node.test_process_background_events(); check_added_monitors(&nodes[0], 1); - reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]); + reconnect_args.send_channel_ready = (true, true); + reconnect_nodes(reconnect_args); // Now resend the payment, delivering the HTLC and actually claiming it this time. This ensures // the payment is not (spuriously) listed as still pending. @@ -817,7 +819,7 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) { nodes[0].node.test_process_background_events(); check_added_monitors(&nodes[0], 1); - reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + reconnect_nodes(ReconnectArgs::new(&nodes[0], &nodes[1])); match nodes[0].node.send_payment_with_route(&new_route, payment_hash, RecipientOnionFields::secret_only(payment_secret), payment_id) { Err(PaymentSendFailure::DuplicatePayment) => {}, @@ -1011,7 +1013,7 @@ fn test_fulfill_restart_failure() { reload_node!(nodes[1], &chan_manager_serialized, &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_1_deserialized); nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id()); - reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + reconnect_nodes(ReconnectArgs::new(&nodes[0], &nodes[1])); nodes[1].node.fail_htlc_backwards(&payment_hash); expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], vec![HTLCDestination::FailedPayment { payment_hash }]); @@ -1736,6 +1738,133 @@ fn do_test_intercepted_payment(test: InterceptTest) { } } +#[test] +fn accept_underpaying_htlcs_config() { + do_accept_underpaying_htlcs_config(1); + do_accept_underpaying_htlcs_config(2); + do_accept_underpaying_htlcs_config(3); +} + +fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) { + let chanmon_cfgs = create_chanmon_cfgs(3); + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + let mut intercept_forwards_config = test_default_channel_config(); + intercept_forwards_config.accept_intercept_htlcs = true; + let mut underpay_config = test_default_channel_config(); + underpay_config.channel_config.accept_underpaying_htlcs = true; + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(underpay_config)]); + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); + + let mut chan_ids = Vec::new(); + for _ in 0..num_mpp_parts { + let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000, 0); + let channel_id = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 2_000_000, 0).0.channel_id; + chan_ids.push(channel_id); + } + + // Send the initial payment. + let amt_msat = 900_000; + let skimmed_fee_msat = 20; + let mut route_hints = Vec::new(); + for _ in 0..num_mpp_parts { + route_hints.push(RouteHint(vec![RouteHintHop { + src_node_id: nodes[1].node.get_our_node_id(), + short_channel_id: nodes[1].node.get_intercept_scid(), + fees: RoutingFees { + base_msat: 1000, + proportional_millionths: 0, + }, + cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA, + htlc_minimum_msat: None, + htlc_maximum_msat: Some(amt_msat / num_mpp_parts as u64 + 5), + }])); + } + let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV) + .with_route_hints(route_hints).unwrap() + .with_bolt11_features(nodes[2].node.invoice_features()).unwrap(); + let route_params = RouteParameters { + payment_params, + final_value_msat: amt_msat, + }; + let (payment_hash, payment_secret) = nodes[2].node.create_inbound_payment(Some(amt_msat), 60 * 60, None).unwrap(); + nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret), + PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); + check_added_monitors!(nodes[0], num_mpp_parts); // one monitor per path + let mut events: Vec = nodes[0].node.get_and_clear_pending_msg_events().into_iter().map(|e| SendEvent::from_event(e)).collect(); + assert_eq!(events.len(), num_mpp_parts); + + // Forward the intercepted payments. + for (idx, ev) in events.into_iter().enumerate() { + nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &ev.msgs[0]); + do_commitment_signed_dance(&nodes[1], &nodes[0], &ev.commitment_msg, false, true); + + let events = nodes[1].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + let (intercept_id, expected_outbound_amt_msat) = match events[0] { + crate::events::Event::HTLCIntercepted { + intercept_id, expected_outbound_amount_msat, payment_hash: pmt_hash, .. + } => { + assert_eq!(pmt_hash, payment_hash); + (intercept_id, expected_outbound_amount_msat) + }, + _ => panic!() + }; + nodes[1].node.forward_intercepted_htlc(intercept_id, &chan_ids[idx], + nodes[2].node.get_our_node_id(), expected_outbound_amt_msat - skimmed_fee_msat).unwrap(); + expect_pending_htlcs_forwardable!(nodes[1]); + let payment_event = { + { + let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let mut events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + SendEvent::from_event(events.remove(0)) + }; + nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]); + do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event.commitment_msg, false, true); + if idx == num_mpp_parts - 1 { + expect_pending_htlcs_forwardable!(nodes[2]); + } + } + + // Claim the payment and check that the skimmed fee is as expected. + let payment_preimage = nodes[2].node.get_payment_preimage(payment_hash, payment_secret).unwrap(); + let events = nodes[2].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + crate::events::Event::PaymentClaimable { + ref payment_hash, ref purpose, amount_msat, counterparty_skimmed_fee_msat, receiver_node_id, .. + } => { + assert_eq!(payment_hash, payment_hash); + assert_eq!(amt_msat - skimmed_fee_msat * num_mpp_parts as u64, amount_msat); + assert_eq!(skimmed_fee_msat * num_mpp_parts as u64, counterparty_skimmed_fee_msat); + assert_eq!(nodes[2].node.get_our_node_id(), receiver_node_id.unwrap()); + match purpose { + crate::events::PaymentPurpose::InvoicePayment { payment_preimage: ev_payment_preimage, + payment_secret: ev_payment_secret, .. } => + { + assert_eq!(payment_preimage, ev_payment_preimage.unwrap()); + assert_eq!(payment_secret, *ev_payment_secret); + }, + _ => panic!(), + } + }, + _ => panic!("Unexpected event"), + } + let mut expected_paths_vecs = Vec::new(); + let mut expected_paths = Vec::new(); + for _ in 0..num_mpp_parts { expected_paths_vecs.push(vec!(&nodes[1], &nodes[2])); } + for i in 0..num_mpp_parts { expected_paths.push(&expected_paths_vecs[i][..]); } + let total_fee_msat = do_claim_payment_along_route_with_extra_penultimate_hop_fees( + &nodes[0], &expected_paths[..], &vec![skimmed_fee_msat as u32; num_mpp_parts][..], false, + payment_preimage); + // The sender doesn't know that the penultimate hop took an extra fee. + expect_payment_sent(&nodes[0], payment_preimage, + Some(Some(total_fee_msat - skimmed_fee_msat * num_mpp_parts as u64)), true); +} + #[derive(PartialEq)] enum AutoRetry { Success, @@ -1776,7 +1905,7 @@ fn do_automatic_retries(test: AutoRetry) { #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; let amt_msat = 1000; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -1995,7 +2124,7 @@ fn auto_retry_partial_failure() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2207,7 +2336,7 @@ fn auto_retry_zero_attempts_send_error() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2247,7 +2376,7 @@ fn fails_paying_after_rejected_by_payee() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2294,7 +2423,7 @@ fn retry_multi_path_single_failed_payment() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2387,7 +2516,7 @@ fn immediate_retry_on_failure() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2475,7 +2604,7 @@ fn no_extra_retries_on_back_to_back_fail() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2677,7 +2806,7 @@ fn test_simple_partial_retry() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -2843,7 +2972,7 @@ fn test_threaded_payment_retries() { let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60; #[cfg(not(feature = "std"))] let payment_expiry_secs = 60 * 60; - let mut invoice_features = InvoiceFeatures::empty(); + let mut invoice_features = Bolt11InvoiceFeatures::empty(); invoice_features.set_variable_length_onion_required(); invoice_features.set_payment_secret_required(); invoice_features.set_basic_mpp_optional(); @@ -3091,7 +3220,7 @@ fn do_claim_from_closed_chan(fail_payment: bool) { final_value_msat: 10_000_000, }; let mut route = nodes[0].router.find_route(&nodes[0].node.get_our_node_id(), &route_params, - None, &nodes[0].node.compute_inflight_htlcs()).unwrap(); + None, nodes[0].node.compute_inflight_htlcs()).unwrap(); // Make sure the route is ordered as the B->D path before C->D route.paths.sort_by(|a, _| if a.hops[0].pubkey == nodes[1].node.get_our_node_id() { std::cmp::Ordering::Less } else { std::cmp::Ordering::Greater }); @@ -3295,9 +3424,11 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) { reload_node!(nodes[3], config, &nodes[3].node.encode(), &[&mon_bd, &mon_cd], persister, new_chain_monitor, nodes_0_deserialized); nodes[1].node.peer_disconnected(&nodes[3].node.get_our_node_id()); - reconnect_nodes(&nodes[1], &nodes[3], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + reconnect_nodes(ReconnectArgs::new(&nodes[1], &nodes[3])); } - reconnect_nodes(&nodes[2], &nodes[3], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + let mut reconnect_args = ReconnectArgs::new(&nodes[2], &nodes[3]); + reconnect_args.send_channel_ready = (true, true); + reconnect_nodes(reconnect_args); // Create a new channel between C and D as A will refuse to retry on the existing one because // it just failed.