+
+ // Update the way of reaching $src_node_id with the given $chan_id (from $dest_node_id),
+ // if this way is cheaper than the already known
+ // (considering the cost to "reach" this channel from the route destination,
+ // the cost of using this channel,
+ // and the cost of routing to the source node of this channel).
+ // Also, consider that htlc_minimum_msat_difference, because we might end up
+ // paying it. Consider the following exploit:
+ // we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path,
+ // and for the other one we picked a 1sat-fee path with htlc_minimum_msat of
+ // 1 BTC. Now, since the latter is more expensive, we gonna try to cut it
+ // by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC
+ // to this channel.
+ // Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here),
+ // but it may require additional tracking - we don't want to double-count
+ // the fees included in $next_hops_path_htlc_minimum_msat, but also
+ // can't use something that may decrease on future hops.
+ let old_cost = cmp::max(old_entry.total_fee_msat, old_entry.path_htlc_minimum_msat);
+ let new_cost = cmp::max(total_fee_msat, path_htlc_minimum_msat);
+
+ if !old_entry.was_processed && new_cost < old_cost {
+ targets.push(new_graph_node);
+ old_entry.next_hops_fee_msat = $next_hops_fee_msat;
+ old_entry.hop_use_fee_msat = hop_use_fee_msat;
+ old_entry.total_fee_msat = total_fee_msat;
+ old_entry.pubkey = $dest_node_id.clone();
+ old_entry.short_channel_id = $chan_id.clone();
+ old_entry.channel_features = $chan_features;
+ old_entry.fee_msat = 0; // This value will be later filled with hop_use_fee_msat of the following channel
+ old_entry.cltv_expiry_delta = $directional_info.cltv_expiry_delta as u32;
+ old_entry.channel_fees = $directional_info.fees;
+ old_entry.htlc_minimum_msat = $directional_info.htlc_minimum_msat;
+ old_entry.path_htlc_minimum_msat = path_htlc_minimum_msat;
+ #[cfg(any(test, feature = "fuzztarget"))]
+ {
+ old_entry.value_contribution_msat = value_contribution_msat;
+ }
+ did_add_update_path_to_src_node = true;
+ } else if old_entry.was_processed && new_cost < old_cost {
+ #[cfg(any(test, feature = "fuzztarget"))]
+ {
+ // If we're skipping processing a node which was previously
+ // processed even though we found another path to it with a
+ // cheaper fee, check that it was because the second path we
+ // found (which we are processing now) has a lower value
+ // contribution due to an HTLC minimum limit.
+ //
+ // e.g. take a graph with two paths from node 1 to node 2, one
+ // through channel A, and one through channel B. Channel A and
+ // B are both in the to-process heap, with their scores set by
+ // a higher htlc_minimum than fee.
+ // Channel A is processed first, and the channels onwards from
+ // node 1 are added to the to-process heap. Thereafter, we pop
+ // Channel B off of the heap, note that it has a much more
+ // restrictive htlc_maximum_msat, and recalculate the fees for
+ // all of node 1's channels using the new, reduced, amount.
+ //
+ // This would be bogus - we'd be selecting a higher-fee path
+ // with a lower htlc_maximum_msat instead of the one we'd
+ // already decided to use.
+ debug_assert!(path_htlc_minimum_msat < old_entry.path_htlc_minimum_msat);
+ debug_assert!(value_contribution_msat < old_entry.value_contribution_msat);
+ }
+ }