match event {
Event::PaymentPathFailed {
- payment_id, payment_hash, rejected_by_dest, path, short_channel_id, retry, ..
+ payment_id, payment_hash, payment_failed_permanently, path, short_channel_id, retry, ..
} => {
if let Some(short_channel_id) = short_channel_id {
let path = path.iter().collect::<Vec<_>>();
if payment_id.is_none() {
log_trace!(self.logger, "Payment {} has no id; not retrying", log_bytes!(payment_hash.0));
- } else if *rejected_by_dest {
+ } else if *payment_failed_permanently {
log_trace!(self.logger, "Payment {} rejected by destination; not retrying", log_bytes!(payment_hash.0));
self.payer.abandon_payment(payment_id.unwrap());
} else if retry.is_none() {
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
use bitcoin_hashes::sha256::Hash as Sha256;
use lightning::ln::PaymentPreimage;
- use lightning::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
+ use lightning::ln::channelmanager;
+ use lightning::ln::features::{ChannelFeatures, NodeFeatures};
use lightning::ln::functional_test_utils::*;
use lightning::ln::msgs::{ChannelMessageHandler, ErrorAction, LightningError};
use lightning::routing::gossip::{EffectiveCapacity, NodeId};
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat),
short_channel_id: None,
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat),
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: true,
path: TestRouter::path_for_value(final_value_msat),
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat / 2),
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: true,
path: TestRouter::path_for_value(final_value_msat),
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: vec![],
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: vec![],
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat / 2),
short_channel_id: None,
payment_id,
payment_hash: PaymentHash(invoice.payment_hash().clone().into_inner()),
network_update: None,
- rejected_by_dest: true,
+ payment_failed_permanently: true,
all_paths_failed: false,
path: vec![],
short_channel_id: None,
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: vec![],
short_channel_id: None,
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: vec![],
short_channel_id: None,
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path,
short_channel_id,
assert_eq!(inflight_map.get(&(2, false)).unwrap().clone(), 64);
// Second path check
- assert_eq!(inflight_map.get(&(1, false)).unwrap().clone(), 64);
+ assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
+ assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64);
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
payment_id, payment_hash, path: route.paths[0].clone()
assert_eq!(inflight_map.get(&(2, false)), None);
// Second path should still be inflight
- assert_eq!(inflight_map.get(&(1, false)).unwrap().clone(), 64)
+ assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
+ assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64)
}
#[test]
let router = TestRouter {};
let scorer = RefCell::new(TestScorer::new()
// 1st invoice, 1st path
- .expect_usage(ChannelUsage { amount_msat: 10, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 20, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 94, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// 1st invoice, 2nd path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// 2nd invoice, 1st path
- .expect_usage(ChannelUsage { amount_msat: 10, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 20, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 94, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// 2nd invoice, 2nd path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 74, effective_capacity: EffectiveCapacity::Unknown } )
);
let logger = TestLogger::new();
let invoice_payer =
let payer = TestPayer::new()
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2))
- .expect_send(Amount::OnRetry(final_value_msat / 2));
+ .expect_send(Amount::OnRetry(final_value_msat / 4));
let final_value_msat = payment_invoice.amount_milli_satoshis().unwrap();
let router = TestRouter {};
let scorer = RefCell::new(TestScorer::new()
// 1st invoice, 1st path
- .expect_usage(ChannelUsage { amount_msat: 10, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 20, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 94, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// 1st invoice, 2nd path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- // Retry 1
- .expect_usage(ChannelUsage { amount_msat: 10, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 20, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ // Retry 1, 1st path
.expect_usage(ChannelUsage { amount_msat: 32, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 52, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 62, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ // Retry 1, 2nd path
.expect_usage(ChannelUsage { amount_msat: 32, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
- // Retry 2
- .expect_usage(ChannelUsage { amount_msat: 10, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 20, inflight_htlc_msat: 96, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 32, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 32, inflight_htlc_msat: 96, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 42, inflight_htlc_msat: 64 + 10, effective_capacity: EffectiveCapacity::Unknown } )
+ // Retry 2, 1st path
+ .expect_usage(ChannelUsage { amount_msat: 16, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 36, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 46, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
+ // Retry 2, 2nd path
+ .expect_usage(ChannelUsage { amount_msat: 16, inflight_htlc_msat: 64 + 32, effective_capacity: EffectiveCapacity::Unknown } )
+ .expect_usage(ChannelUsage { amount_msat: 26, inflight_htlc_msat: 74 + 32 + 10, effective_capacity: EffectiveCapacity::Unknown } )
);
let logger = TestLogger::new();
let invoice_payer =
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat),
short_channel_id: None,
payment_id,
payment_hash,
network_update: None,
- rejected_by_dest: false,
+ payment_failed_permanently: false,
all_paths_failed: false,
path: TestRouter::path_for_value(final_value_msat / 2),
short_channel_id: None,
retry: Some(RouteParameters {
- final_value_msat: final_value_msat / 2,
+ final_value_msat: final_value_msat / 4,
..TestRouter::retry_for_invoice(&payment_invoice)
}),
});
// Only the second path, which failed with `MonitorUpdateFailed` should be added to our
// inflight map because retries are disabled.
- assert_eq!(inflight_map.len(), 1);
+ assert_eq!(inflight_map.len(), 2);
}
#[test]
invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
- // All paths successful, hence we check of the existence of all 4 hops.
- assert_eq!(inflight_map.len(), 4);
+ // All paths successful, hence we check of the existence of all 5 hops.
+ assert_eq!(inflight_map.len(), 5);
}
struct TestRouter;
cltv_expiry_delta: 0
},
],
- vec![RouteHop {
- pubkey: PublicKey::from_slice(&hex::decode("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap(),
- channel_features: ChannelFeatures::empty(),
- node_features: NodeFeatures::empty(),
- short_channel_id: 1, fee_msat: final_value_msat / 2, cltv_expiry_delta: 144
- }],
+ vec![
+ RouteHop {
+ pubkey: PublicKey::from_slice(&hex::decode("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255").unwrap()[..]).unwrap(),
+ channel_features: ChannelFeatures::empty(),
+ node_features: NodeFeatures::empty(),
+ short_channel_id: 3,
+ fee_msat: 10,
+ cltv_expiry_delta: 144
+ },
+ RouteHop {
+ pubkey: PublicKey::from_slice(&hex::decode("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap(),
+ channel_features: ChannelFeatures::empty(),
+ node_features: NodeFeatures::empty(),
+ short_channel_id: 4,
+ fee_msat: final_value_msat / 2,
+ cltv_expiry_delta: 144
+ }
+ ],
],
payment_params: None,
}
// Simulate calling the Scorer just as you would in find_route
let route = Self::route_for_value(route_params.final_value_msat);
for path in route.paths {
- for hop in path {
+ let mut aggregate_msat = 0u64;
+ for (idx, hop) in path.iter().rev().enumerate() {
+ aggregate_msat += hop.fee_msat;
let usage = ChannelUsage {
- amount_msat: hop.fee_msat,
+ amount_msat: aggregate_msat,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Unknown,
};
- scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage);
+
+ // Since the path is reversed, the last element in our iteration is the first
+ // hop.
+ if idx == path.len() - 1 {
+ scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage);
+ } else {
+ scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path[idx + 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage);
+ }
}
}
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chans = nodes[0].node.list_usable_channels();
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[0].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 10_000,
cltv_expiry_delta: 100,
}],
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[1].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
cltv_expiry_delta: 100,
}],
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chans = nodes[0].node.list_usable_channels();
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[0].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
cltv_expiry_delta: 100,
}],
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_2_scid = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 0, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_2_scid = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_1_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 0,
cltv_expiry_delta: 100,
}, RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_2_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_000,
cltv_expiry_delta: 100,
}],
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_1_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 0,
cltv_expiry_delta: 100,
}, RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_2_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_000,
cltv_expiry_delta: 100,
}]
// treated this as "HTLC complete" and dropped the retry counter, causing us to retry again
// if the final HTLC failed.
expected_events.borrow_mut().push_back(&|ev: &Event| {
- if let Event::PaymentPathFailed { rejected_by_dest, all_paths_failed, .. } = ev {
- assert!(!rejected_by_dest);
+ if let Event::PaymentPathFailed { payment_failed_permanently, all_paths_failed, .. } = ev {
+ assert!(!payment_failed_permanently);
assert!(all_paths_failed);
} else { panic!("Unexpected event"); }
});
commitment_signed_dance!(nodes[0], nodes[1], &bs_fail_update.commitment_signed, false, true);
expected_events.borrow_mut().push_back(&|ev: &Event| {
- if let Event::PaymentPathFailed { rejected_by_dest, all_paths_failed, .. } = ev {
- assert!(!rejected_by_dest);
+ if let Event::PaymentPathFailed { payment_failed_permanently, all_paths_failed, .. } = ev {
+ assert!(!payment_failed_permanently);
assert!(all_paths_failed);
} else { panic!("Unexpected event"); }
});