+ // For each hop in the path, we add new entries to the `log_loss_sum` and
+ // `result_count` state variables, updating entries with the given flags.
+ let mut update_data_with_result = |mut flags, mut probability: f64, success| {
+ if success {
+ flags |= SUCCESS;
+ } else {
+ flags &= !SUCCESS;
+ }
+ if !success { probability = 1.0 - probability; }
+ if probability < 0.01 {
+ // While the model really needs to be tuned to avoid being so incredibly
+ // overconfident, in the mean time we cheat a bit to avoid infinite results.
+ probability = 0.01;
+ }
+ state.log_loss_sum[flags] -= probability.log2();
+ state.result_count[flags] += 1;
+ };
+
+ // At each hop, we add two new entries - one for the LDK historical model and one for the naive
+ // live bounds model.
+ let mut evaluate_hop = |hop: &DirectedChannel, success| {
+ let hist_model_probability =
+ state.scorer.historical_estimated_payment_success_probability(hop.short_channel_id, &hop.dst_node_id, hop.amount_msat, &Default::default(), true)
+ .expect("We should have some estimated probability, even without history data");
+ let have_hist_results =
+ state.scorer.historical_estimated_payment_success_probability(hop.short_channel_id, &hop.dst_node_id, hop.amount_msat, &Default::default(), false)
+ .is_some();
+ let flags = if have_hist_results { 0 } else { NO_DATA };
+ update_data_with_result(flags, hist_model_probability, success);
+
+ let live_model_probability =
+ state.scorer.live_estimated_payment_success_probability(hop.short_channel_id, &hop.dst_node_id, hop.amount_msat, &Default::default())
+ .expect("We should have some estimated probability, even without past data");
+ let have_live_data = state.scorer.estimated_channel_liquidity_range(hop.short_channel_id, &hop.dst_node_id).is_some();
+ let flags = LIVE | if have_live_data { 0 } else { NO_DATA };
+ update_data_with_result(flags, live_model_probability, success);
+ };
+
+ // Evaluate the model by passing each hop which succeeded as well as the final failing hop to
+ // `evaluate_hop`.