use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch};
use ln::features::{InitFeatures, NodeFeatures};
-use routing::router::{Payee, Route, RouteHop, RouteParameters};
+use routing::router::{Payee, Route, RouteHop, RoutePath, RouteParameters};
use ln::msgs;
use ln::msgs::NetAddress;
use ln::onion_utils;
payment_hash: PaymentHash,
payment_secret: Option<PaymentSecret>,
pending_amt_msat: u64,
+ /// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
+ pending_fee_msat: Option<u64>,
/// The total payment amount across all paths, used to verify that a retry is not overpaying.
total_msat: u64,
/// Our best known block height at the time this payment was initiated.
_ => false,
}
}
+ fn get_pending_fee_msat(&self) -> Option<u64> {
+ match self {
+ PendingOutboundPayment::Retryable { pending_fee_msat, .. } => pending_fee_msat.clone(),
+ _ => None,
+ }
+ }
fn mark_fulfilled(&mut self) {
let mut session_privs = HashSet::new();
}
};
if remove_res {
- if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, .. } = self {
+ if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
let path = path.expect("Fulfilling a payment should always come with a path");
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
*pending_amt_msat -= path_last_hop.fee_msat;
+ if let Some(fee_msat) = pending_fee_msat.as_mut() {
+ *fee_msat -= path.get_path_fees();
+ }
}
}
remove_res
PendingOutboundPayment::Fulfilled { .. } => false
};
if insert_res {
- if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, .. } = self {
+ if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
*pending_amt_msat += path_last_hop.fee_msat;
+ if let Some(fee_msat) = pending_fee_msat.as_mut() {
+ *fee_msat += path.get_path_fees();
+ }
}
}
insert_res
let payment = payment_entry.or_insert_with(|| PendingOutboundPayment::Retryable {
session_privs: HashSet::new(),
pending_amt_msat: 0,
+ pending_fee_msat: Some(0),
payment_hash: *payment_hash,
payment_secret: *payment_secret,
starting_block_height: self.best_block.read().unwrap().height(),
let mut session_priv_bytes = [0; 32];
session_priv_bytes.copy_from_slice(&session_priv[..]);
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
- let found_payment = if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
+ if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
let found_payment = !payment.get().is_fulfilled();
+ let fee_paid_msat = payment.get().get_pending_fee_msat();
payment.get_mut().mark_fulfilled();
if from_onchain {
// We currently immediately remove HTLCs which were fulfilled on-chain.
payment.remove();
}
}
- found_payment
- } else { false };
- if found_payment {
- let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
- self.pending_events.lock().unwrap().push(
- events::Event::PaymentSent {
- payment_id: Some(payment_id),
- payment_preimage,
- payment_hash: payment_hash
- }
- );
+ if found_payment {
+ let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+ self.pending_events.lock().unwrap().push(
+ events::Event::PaymentSent {
+ payment_id: Some(payment_id),
+ payment_preimage,
+ payment_hash: payment_hash,
+ fee_paid_msat,
+ }
+ );
+ }
} else {
log_trace!(self.logger, "Received duplicative fulfill for HTLC with payment_preimage {}", log_bytes!(payment_preimage.0));
}
},
(2, Retryable) => {
(0, session_privs, required),
+ (1, pending_fee_msat, option),
(2, payment_hash, required),
(4, payment_secret, option),
(6, total_msat, required),
if newly_added { "Added" } else { "Had" }, path_amt, log_bytes!(session_priv_bytes), log_bytes!(htlc.payment_hash.0));
},
hash_map::Entry::Vacant(entry) => {
+ let path_fee = path.get_path_fees();
entry.insert(PendingOutboundPayment::Retryable {
session_privs: [session_priv_bytes].iter().map(|a| *a).collect(),
payment_hash: htlc.payment_hash,
payment_secret,
pending_amt_msat: path_amt,
+ pending_fee_msat: Some(path_fee),
total_msat: path_amt,
starting_block_height: best_block_height,
});
// further events will be generated for subsequence path successes.
let events = nodes[0].node.get_and_clear_pending_events();
match events[0] {
- Event::PaymentSent { payment_id: ref id, payment_preimage: ref preimage, payment_hash: ref hash } => {
+ Event::PaymentSent { payment_id: ref id, payment_preimage: ref preimage, payment_hash: ref hash, .. } => {
assert_eq!(Some(payment_id), *id);
assert_eq!(payment_preimage, *preimage);
assert_eq!(our_payment_hash, *hash);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let scorer = Scorer::new(0);
+ let scorer = Scorer::with_fixed_penalty(0);
// To start (1), send a regular payment but don't claim it.
let expected_route = [&nodes[1]];
final_cltv_expiry_delta: TEST_FINAL_CLTV,
};
let route = find_route(
- &nodes[0].node.get_our_node_id(), ¶ms,
- &nodes[0].net_graph_msg_handler.network_graph, None, nodes[0].logger, &scorer
+ &nodes[0].node.get_our_node_id(), ¶ms, nodes[0].network_graph, None,
+ nodes[0].logger, &scorer
).unwrap();
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
check_added_monitors!(nodes[0], 1);
// To start (2), send a keysend payment but don't claim it.
let payment_preimage = PaymentPreimage([42; 32]);
let route = find_route(
- &nodes[0].node.get_our_node_id(), ¶ms,
- &nodes[0].net_graph_msg_handler.network_graph, None, nodes[0].logger, &scorer
+ &nodes[0].node.get_our_node_id(), ¶ms, nodes[0].network_graph, None,
+ nodes[0].logger, &scorer
).unwrap();
let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
check_added_monitors!(nodes[0], 1);
final_value_msat: 10000,
final_cltv_expiry_delta: 40,
};
- let network_graph = &nodes[0].net_graph_msg_handler.network_graph;
+ let network_graph = nodes[0].network_graph;
let first_hops = nodes[0].node.list_usable_channels();
- let scorer = Scorer::new(0);
+ let scorer = Scorer::with_fixed_penalty(0);
let route = find_route(
&payer_pubkey, ¶ms, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
nodes[0].logger, &scorer
final_value_msat: 10000,
final_cltv_expiry_delta: 40,
};
- let network_graph = &nodes[0].net_graph_msg_handler.network_graph;
+ let network_graph = nodes[0].network_graph;
let first_hops = nodes[0].node.list_usable_channels();
- let scorer = Scorer::new(0);
+ let scorer = Scorer::with_fixed_penalty(0);
let route = find_route(
&payer_pubkey, ¶ms, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
nodes[0].logger, &scorer
let usable_channels = $node_a.list_usable_channels();
let payee = Payee::new($node_b.get_our_node_id())
.with_features(InvoiceFeatures::known());
- let scorer = Scorer::new(0);
+ let scorer = Scorer::with_fixed_penalty(0);
let route = get_route(&$node_a.get_our_node_id(), &payee, &dummy_graph,
Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap();