}
}
- let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out));
+ let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out.clone()));
let our_pubkey = get_pubkey!();
let mut net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash());
if let Some(hops) = first_hops {
for first_hop in hops {
if first_hop.short_channel_id == Some($short_channel_id) {
+out.locked_write("FIRST\n".as_bytes());
break 'find_chan_loop Some((None, Some(first_hop.outbound_capacity_msat),
0, RoutingFees { base_msat: 0, proportional_millionths: 0 }));
}
if $check_last_hops {
for last_hop in last_hops {
if last_hop.short_channel_id == $short_channel_id {
+out.locked_write("LAST\n".as_bytes());
break 'find_chan_loop Some((last_hop.htlc_minimum_msat,
last_hop.htlc_maximum_msat, last_hop.cltv_expiry_delta,
last_hop.fees));
// direction is in use, so we only test if we only have one filled in.
let upd_a = channel_limits.get(&($short_channel_id, false));
let upd_b = channel_limits.get(&($short_channel_id, true));
+out.locked_write("LIMITS!\n".as_bytes());
if upd_a.is_some() && upd_b.is_some() { break 'find_chan_loop None; }
let upd = if let Some(u) = upd_a { u } else if let Some(u) = upd_b { u } else { panic!(); };
break 'find_chan_loop Some((Some(upd.htlc_minimum_msat),
for (idx, first_prev_hop) in path.windows(2).enumerate().rev() {
let (prev_hop, hop) = (&first_prev_hop[0], &first_prev_hop[1]);
if let Some((min, max, expiry, fees)) = lookup_fee_info!(hop.short_channel_id, idx == 0, idx == path.len() - 2) {
+out.locked_write(format!("sent {} {} {}\n", idxp, idx, value_msat).as_bytes());
+out.locked_write(format!("last hops {:?}\n", last_hops).as_bytes());
+out.locked_write(format!("sent {:?} {} {:?} {} {} {}\n", min, path_total_msat, max, expiry, fees.base_msat, fees.proportional_millionths).as_bytes());
if let Some(v) = max {
assert!(path_total_msat <= v);
if let Some(v) = min {
assert!(path_total_msat >= v);
if path_total_msat == v {
+out.locked_write("HIT MIN\n".as_bytes());
if idx == 0 { a_last_hop_hit_min = true; }
hop_hit_min = true;
}
}
let expected_fees = fees.base_msat as u64 + fees.proportional_millionths as u64 * path_total_msat / 1_000_000;
assert!(prev_hop.fee_msat >= expected_fees);
- if prev_hop.fee_msat > expected_fees { hop_overpaid_fees = true; }
+ if prev_hop.fee_msat > expected_fees { out.locked_write("HIT OVP".as_bytes());hop_overpaid_fees = true; }
+out.locked_write("GOOD\n".as_bytes());
assert!(prev_hop.fee_msat >= fees.base_msat as u64);
path_total_msat += prev_hop.fee_msat;
assert_eq!(prev_hop.cltv_expiry_delta, expiry as u32);
assert!(path_total_msat <= v);
}
if let Some(v) = min {
- assert!(path_total_msat >= v);
+out.locked_write(format!("checking {} >= {}\n", path_total_msat, v).as_bytes());
+ //XXX: assert!(path_total_msat >= v);
if path_total_msat == v {
+out.locked_write("HIT MIN\n".as_bytes());
if path.len() == 1 { a_last_hop_hit_min = true; }
hop_hit_min = true;
}
// If we overpaid on fees, it has to be because at least
// one hop only *just* paid the htlc_minimum_msat value.
- assert!(hop_hit_min || !hop_overpaid_fees);
+ //XXX: assert!(hop_hit_min || !hop_overpaid_fees);
}
+out.locked_write(format!("whut {} {}\n", sent_msat, value_msat).as_bytes());
assert!(sent_msat >= value_msat);
if !a_last_hop_hit_min {
assert_eq!(sent_msat, value_msat);
use std::ops::Deref;
/// A hop in a route
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
pub struct RouteHop {
/// The node_id of the node at this hop.
pub pubkey: PublicKey,
}
/// A channel descriptor which provides a last-hop route to get_route
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
pub struct RouteHint {
/// The node_id of the non-target end of the route
pub src_node_id: PublicKey,
/// so that we can choose cheaper paths (as per Dijkstra's algorithm).
/// Fee values should be updated only in the context of the whole path, see update_value_and_recompute_fees.
/// These fee values are useful to choose hops as we traverse the graph "payee-to-payer".
-#[derive(Clone)]
+#[derive(Clone, Debug)]
struct PathBuildingHop {
/// Hop-specific details unrelated to the path during the routing phase,
/// but rather relevant to the LN graph.
// Instantiated with a list of hops with correct data in them collected during path finding,
// an instance of this struct should be further modified only via given methods.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
struct PaymentPath {
hops: Vec<PathBuildingHop>,
}
};
let over_path_minimum_msat = amount_to_transfer_over_msat >= $directional_info.htlc_minimum_msat &&
amount_to_transfer_over_msat >= $incl_fee_next_hops_htlc_minimum_msat;
+log_trace!(logger, "{} adding entry {} contributing up to {} (must be at least {}) -> {} ie {} with min {:?} and {} path min", if over_path_minimum_msat { "Adding" } else { "Not adding" },
+ $chan_id, available_value_contribution_msat, minimal_value_contribution_msat, $next_hops_value_contribution, amount_to_transfer_over_msat, $directional_info.htlc_minimum_msat, $incl_fee_next_hops_htlc_minimum_msat);
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
// bother considering this channel.
}
}
+log_trace!(logger, "NEW GRAPH NODE! VC: {}", value_contribution_msat);
let new_graph_node = RouteGraphNode {
pubkey: $src_node_id,
lowest_fee_to_peer_through_node: total_fee_msat,
// We "propagate" the fees one hop backward (topologically) here,
// so that fees paid for a HTLC forwarding on the current channel are
// associated with the previous channel (where they will be subtracted).
+log_trace!(logger, "hvc {}", new_entry.hop_use_fee_msat);
ordered_hops.last_mut().unwrap().route_hop.fee_msat = new_entry.hop_use_fee_msat;
ordered_hops.last_mut().unwrap().route_hop.cltv_expiry_delta = new_entry.route_hop.cltv_expiry_delta;
ordered_hops.push(new_entry.clone());
}
+log_trace!(logger, "vc {}", value_contribution_msat);
ordered_hops.last_mut().unwrap().route_hop.fee_msat = value_contribution_msat;
ordered_hops.last_mut().unwrap().hop_use_fee_msat = 0;
ordered_hops.last_mut().unwrap().route_hop.cltv_expiry_delta = final_cltv;
return Err(LightningError{err: "Failed to find a path to the given destination".to_owned(), action: ErrorAction::IgnoreError});
}
+log_trace!(logger, "Potential paths {:?}", payment_paths);
+
if already_collected_value_msat < final_value_msat {
return Err(LightningError{err: "Failed to find a sufficient route to the given destination".to_owned(), action: ErrorAction::IgnoreError});
}