Skip to content

Commit 04ae834

Browse files
committed
Test the RouteParameters passed to TestRouter
`TestRouter` allows us to simply select the `Route` that will be returned in the next `find_route` call, but it does so without any checking of what was *requested* for the call. This makes it a somewhat dubious test utility as it very helpfully ensures we ignore errors in the routes we're looking for. Instead, we require users of `TestRouter` pass a `RouteParameters` to `expect_find_route`, which we compare against the requested parameters passed to `find_route`.
1 parent 883ad54 commit 04ae834

File tree

3 files changed

+99
-75
lines changed

3 files changed

+99
-75
lines changed

lightning/src/ln/outbound_payment.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,15 +1189,16 @@ mod tests {
11891189
let secp_ctx = Secp256k1::new();
11901190
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
11911191

1192-
router.expect_find_route(Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }));
1193-
11941192
let payment_params = PaymentParameters::from_node_id(
11951193
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0);
11961194
let route_params = RouteParameters {
11971195
payment_params,
11981196
final_value_msat: 0,
11991197
final_cltv_expiry_delta: 0,
12001198
};
1199+
router.expect_find_route(route_params.clone(),
1200+
Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }));
1201+
12011202
let err = if on_retry {
12021203
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), None, PaymentId([0; 32]),
12031204
&Route { paths: vec![], payment_params: None }, Retry::Attempts(1), Some(route_params.clone()),

lightning/src/ln/payment_tests.rs

Lines changed: 90 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ fn auto_retry_partial_failure() {
18441844
cltv_expiry_delta: 100,
18451845
}],
18461846
],
1847-
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
1847+
payment_params: Some(route_params.payment_params.clone()),
18481848
};
18491849
let retry_1_route = Route {
18501850
paths: vec![
@@ -1865,7 +1865,7 @@ fn auto_retry_partial_failure() {
18651865
cltv_expiry_delta: 100,
18661866
}],
18671867
],
1868-
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
1868+
payment_params: Some(route_params.payment_params.clone()),
18691869
};
18701870
let retry_2_route = Route {
18711871
paths: vec![
@@ -1878,11 +1878,17 @@ fn auto_retry_partial_failure() {
18781878
cltv_expiry_delta: 100,
18791879
}],
18801880
],
1881-
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
1881+
payment_params: Some(route_params.payment_params.clone()),
18821882
};
1883-
nodes[0].router.expect_find_route(Ok(send_route));
1884-
nodes[0].router.expect_find_route(Ok(retry_1_route));
1885-
nodes[0].router.expect_find_route(Ok(retry_2_route));
1883+
nodes[0].router.expect_find_route(route_params.clone(), Ok(send_route));
1884+
nodes[0].router.expect_find_route(RouteParameters {
1885+
payment_params: route_params.payment_params.clone(),
1886+
final_value_msat: amt_msat / 2, final_cltv_expiry_delta: TEST_FINAL_CLTV
1887+
}, Ok(retry_1_route));
1888+
nodes[0].router.expect_find_route(RouteParameters {
1889+
payment_params: route_params.payment_params.clone(),
1890+
final_value_msat: amt_msat / 4, final_cltv_expiry_delta: TEST_FINAL_CLTV
1891+
}, Ok(retry_2_route));
18861892

18871893
// Send a payment that will partially fail on send, then partially fail on retry, then succeed.
18881894
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(3)).unwrap();
@@ -2074,6 +2080,27 @@ fn retry_multi_path_single_failed_payment() {
20742080

20752081
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
20762082
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2083+
2084+
let amt_msat = 100_010_000;
2085+
2086+
let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], amt_msat);
2087+
#[cfg(feature = "std")]
2088+
let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
2089+
#[cfg(not(feature = "std"))]
2090+
let payment_expiry_secs = 60 * 60;
2091+
let mut invoice_features = InvoiceFeatures::empty();
2092+
invoice_features.set_variable_length_onion_required();
2093+
invoice_features.set_payment_secret_required();
2094+
invoice_features.set_basic_mpp_optional();
2095+
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
2096+
.with_expiry_time(payment_expiry_secs as u64)
2097+
.with_features(invoice_features);
2098+
let route_params = RouteParameters {
2099+
payment_params: payment_params.clone(),
2100+
final_value_msat: amt_msat,
2101+
final_cltv_expiry_delta: TEST_FINAL_CLTV,
2102+
};
2103+
20772104
let chans = nodes[0].node.list_usable_channels();
20782105
let mut route = Route {
20792106
paths: vec![
@@ -2094,15 +2121,37 @@ fn retry_multi_path_single_failed_payment() {
20942121
cltv_expiry_delta: 100,
20952122
}],
20962123
],
2097-
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
2124+
payment_params: Some(payment_params),
20982125
};
2099-
nodes[0].router.expect_find_route(Ok(route.clone()));
2126+
nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
21002127
// On retry, split the payment across both channels.
21012128
route.paths[0][0].fee_msat = 50_000_001;
21022129
route.paths[1][0].fee_msat = 50_000_000;
2103-
nodes[0].router.expect_find_route(Ok(route.clone()));
2130+
nodes[0].router.expect_find_route(RouteParameters {
2131+
payment_params: route.payment_params.clone().unwrap(),
2132+
// Note that the second request here requests the amount we originally failed to send,
2133+
// not the amount remaining on the full payment, which should be changed.
2134+
final_value_msat: 100_000_001, final_cltv_expiry_delta: TEST_FINAL_CLTV
2135+
}, Ok(route.clone()));
21042136

2105-
let amt_msat = 100_010_000;
2137+
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
2138+
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
2139+
assert_eq!(htlc_msgs.len(), 2);
2140+
check_added_monitors!(nodes[0], 2);
2141+
}
2142+
2143+
#[test]
2144+
fn immediate_retry_on_failure() {
2145+
// Tests that we can/will retry immediately after a failure
2146+
let chanmon_cfgs = create_chanmon_cfgs(2);
2147+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2148+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
2149+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2150+
2151+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2152+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2153+
2154+
let amt_msat = 100_000_001;
21062155
let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], amt_msat);
21072156
#[cfg(feature = "std")]
21082157
let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
@@ -2121,22 +2170,6 @@ fn retry_multi_path_single_failed_payment() {
21212170
final_cltv_expiry_delta: TEST_FINAL_CLTV,
21222171
};
21232172

2124-
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
2125-
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
2126-
assert_eq!(htlc_msgs.len(), 2);
2127-
check_added_monitors!(nodes[0], 2);
2128-
}
2129-
2130-
#[test]
2131-
fn immediate_retry_on_failure() {
2132-
// Tests that we can/will retry immediately after a failure
2133-
let chanmon_cfgs = create_chanmon_cfgs(2);
2134-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2135-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
2136-
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2137-
2138-
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2139-
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
21402173
let chans = nodes[0].node.list_usable_channels();
21412174
let mut route = Route {
21422175
paths: vec![
@@ -2151,32 +2184,16 @@ fn immediate_retry_on_failure() {
21512184
],
21522185
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
21532186
};
2154-
nodes[0].router.expect_find_route(Ok(route.clone()));
2187+
nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
21552188
// On retry, split the payment across both channels.
21562189
route.paths.push(route.paths[0].clone());
21572190
route.paths[0][0].short_channel_id = chans[1].short_channel_id.unwrap();
21582191
route.paths[0][0].fee_msat = 50_000_000;
21592192
route.paths[1][0].fee_msat = 50_000_001;
2160-
nodes[0].router.expect_find_route(Ok(route.clone()));
2161-
2162-
let amt_msat = 100_010_000;
2163-
let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], amt_msat);
2164-
#[cfg(feature = "std")]
2165-
let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
2166-
#[cfg(not(feature = "std"))]
2167-
let payment_expiry_secs = 60 * 60;
2168-
let mut invoice_features = InvoiceFeatures::empty();
2169-
invoice_features.set_variable_length_onion_required();
2170-
invoice_features.set_payment_secret_required();
2171-
invoice_features.set_basic_mpp_optional();
2172-
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
2173-
.with_expiry_time(payment_expiry_secs as u64)
2174-
.with_features(invoice_features);
2175-
let route_params = RouteParameters {
2176-
payment_params,
2177-
final_value_msat: amt_msat,
2178-
final_cltv_expiry_delta: TEST_FINAL_CLTV,
2179-
};
2193+
nodes[0].router.expect_find_route(RouteParameters {
2194+
payment_params: route_params.payment_params.clone(),
2195+
final_value_msat: amt_msat, final_cltv_expiry_delta: TEST_FINAL_CLTV
2196+
}, Ok(route.clone()));
21802197

21812198
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
21822199
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
@@ -2208,6 +2225,25 @@ fn no_extra_retries_on_back_to_back_fail() {
22082225
let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0).0.contents.short_channel_id;
22092226
let chan_2_scid = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 0).0.contents.short_channel_id;
22102227

2228+
let amt_msat = 200_000_000;
2229+
let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], amt_msat);
2230+
#[cfg(feature = "std")]
2231+
let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
2232+
#[cfg(not(feature = "std"))]
2233+
let payment_expiry_secs = 60 * 60;
2234+
let mut invoice_features = InvoiceFeatures::empty();
2235+
invoice_features.set_variable_length_onion_required();
2236+
invoice_features.set_payment_secret_required();
2237+
invoice_features.set_basic_mpp_optional();
2238+
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
2239+
.with_expiry_time(payment_expiry_secs as u64)
2240+
.with_features(invoice_features);
2241+
let route_params = RouteParameters {
2242+
payment_params,
2243+
final_value_msat: amt_msat,
2244+
final_cltv_expiry_delta: TEST_FINAL_CLTV,
2245+
};
2246+
22112247
let mut route = Route {
22122248
paths: vec![
22132249
vec![RouteHop {
@@ -2243,29 +2279,15 @@ fn no_extra_retries_on_back_to_back_fail() {
22432279
],
22442280
payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
22452281
};
2246-
nodes[0].router.expect_find_route(Ok(route.clone()));
2282+
nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
22472283
// On retry, we'll only be asked for one path
22482284
route.paths.remove(1);
2249-
nodes[0].router.expect_find_route(Ok(route.clone()));
2250-
2251-
let amt_msat = 100_010_000;
2252-
let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], amt_msat);
2253-
#[cfg(feature = "std")]
2254-
let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
2255-
#[cfg(not(feature = "std"))]
2256-
let payment_expiry_secs = 60 * 60;
2257-
let mut invoice_features = InvoiceFeatures::empty();
2258-
invoice_features.set_variable_length_onion_required();
2259-
invoice_features.set_payment_secret_required();
2260-
invoice_features.set_basic_mpp_optional();
2261-
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
2262-
.with_expiry_time(payment_expiry_secs as u64)
2263-
.with_features(invoice_features);
2264-
let route_params = RouteParameters {
2265-
payment_params,
2266-
final_value_msat: amt_msat,
2267-
final_cltv_expiry_delta: TEST_FINAL_CLTV,
2268-
};
2285+
let mut second_payment_params = route_params.payment_params.clone();
2286+
second_payment_params.previously_failed_channels = vec![chan_2_scid, chan_2_scid];
2287+
nodes[0].router.expect_find_route(RouteParameters {
2288+
payment_params: second_payment_params,
2289+
final_value_msat: amt_msat, final_cltv_expiry_delta: TEST_FINAL_CLTV,
2290+
}, Ok(route.clone()));
22692291

22702292
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
22712293
let htlc_updates = SendEvent::from_node(&nodes[0]);

lightning/src/util/test_utils.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,17 @@ impl chaininterface::FeeEstimator for TestFeeEstimator {
7777

7878
pub struct TestRouter<'a> {
7979
pub network_graph: Arc<NetworkGraph<&'a TestLogger>>,
80-
pub next_routes: Mutex<VecDeque<Result<Route, LightningError>>>,
80+
pub next_routes: Mutex<VecDeque<(RouteParameters, Result<Route, LightningError>)>>,
8181
}
8282

8383
impl<'a> TestRouter<'a> {
8484
pub fn new(network_graph: Arc<NetworkGraph<&'a TestLogger>>) -> Self {
8585
Self { network_graph, next_routes: Mutex::new(VecDeque::new()), }
8686
}
8787

88-
pub fn expect_find_route(&self, result: Result<Route, LightningError>) {
88+
pub fn expect_find_route(&self, query: RouteParameters, result: Result<Route, LightningError>) {
8989
let mut expected_routes = self.next_routes.lock().unwrap();
90-
expected_routes.push_back(result);
90+
expected_routes.push_back((query, result));
9191
}
9292
}
9393

@@ -96,8 +96,9 @@ impl<'a> Router for TestRouter<'a> {
9696
&self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&channelmanager::ChannelDetails]>,
9797
inflight_htlcs: &InFlightHtlcs
9898
) -> Result<Route, msgs::LightningError> {
99-
if let Some(find_route_res) = self.next_routes.lock().unwrap().pop_front() {
100-
return find_route_res
99+
if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() {
100+
assert_eq!(find_route_query, *params);
101+
return find_route_res;
101102
}
102103
let logger = TestLogger::new();
103104
find_route(

0 commit comments

Comments
 (0)