Skip to content

Commit 330f51a

Browse files
committed
askrene: make increase_flows function more generic.
Rewrite it, so it properly takes into account interactions between flows by using reservations. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent a8a6a44 commit 330f51a

File tree

1 file changed

+76
-36
lines changed

1 file changed

+76
-36
lines changed

plugins/askrene/refine.c

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -383,54 +383,94 @@ static struct amount_msat remove_excess(struct flow ***flows,
383383
return all_deliver;
384384
}
385385

386+
/* Return true (and set shortage) if flow doesn't deliver this much */
387+
static bool flows_short(struct flow **flows,
388+
struct amount_msat deliver,
389+
struct amount_msat *shortage)
390+
{
391+
return amount_msat_sub(shortage, deliver, sum_all_deliver(flows))
392+
&& !amount_msat_is_zero(*shortage);
393+
}
394+
386395
/* It increases the flows to meet the deliver target. It does not increase any
387-
* flow beyond the tolerance fraction. It doesn't increase any flow above its
388-
* max_deliverable value.
389-
* Returns the total delivery amount. */
390-
static struct amount_msat increase_flows(const struct route_query *rq,
391-
struct flow **flows,
392-
struct amount_msat deliver,
393-
double tolerance)
396+
* flow beyond the tolerance fraction (unless negative).
397+
* Returns true if it managed to increase total amount to "deliver". */
398+
static bool increase_flows(const struct route_query *rq,
399+
struct flow **flows,
400+
struct amount_msat deliver,
401+
double tolerance)
394402
{
395-
if (tal_count(flows) == 0)
396-
return AMOUNT_MSAT(0);
403+
const tal_t *working_ctx = tal(NULL, tal_t);
404+
struct amount_msat shortage, *ceiling;
397405

398-
struct amount_msat all_deliver, defect;
399-
all_deliver = sum_all_deliver(flows);
406+
/* Record max we can deliver for each flow, so we don't exceed it */
407+
ceiling = tal_arr(working_ctx, struct amount_msat, tal_count(flows));
408+
for (size_t i = 0; i < tal_count(flows); i++) {
409+
if (tolerance < 0)
410+
ceiling[i] = deliver;
411+
else if (!amount_msat_scale(&ceiling[i], flows[i]->delivers, 1.0 + tolerance))
412+
abort();
413+
}
400414

401-
/* early exit: target is already met */
402-
if (!amount_msat_sub(&defect, deliver, all_deliver) ||
403-
amount_msat_is_zero(defect))
404-
return all_deliver;
415+
/* This is naive, but since flows can overlap, increasing one
416+
* can alter the remaining capacity of the others! */
417+
while (flows_short(flows, deliver, &shortage)) {
418+
size_t best_flownum = 0;
419+
struct amount_msat best_remaining = AMOUNT_MSAT(0);
420+
struct reserve_hop **reservations;
421+
struct amount_msat addition;
422+
423+
/* Because flows can interact, we reserve them all, removing one at a time. */
424+
reservations = tal_arr(NULL, struct reserve_hop *, tal_count(flows));
425+
for (size_t i = 0; i < tal_count(flows); i++) {
426+
reservations[i] = new_reservations(reservations, rq);
427+
create_flow_reservations(rq, &reservations[i], flows[i]);
428+
}
405429

406-
asort(flows, tal_count(flows), revcmp_flows, NULL);
430+
/* Find flow with most excess capacity. */
431+
for (size_t i = 0; i < tal_count(flows); i++) {
432+
struct amount_msat capacity, remaining;
407433

408-
all_deliver = AMOUNT_MSAT(0);
409-
for (size_t i = 0;
410-
i < tal_count(flows) && !amount_msat_is_zero(defect); i++) {
411-
struct flow *flow = flows[i];
412-
struct amount_msat can_add = defect, amt;
434+
/* flow_max_deliverable considers reservations *and*
435+
* htlc_max. So remove this reservation, to get the
436+
* real maximum for one flow, then replace it. */
437+
tal_free(reservations[i]);
438+
capacity = flow_max_deliverable(rq, flows[i], NULL);
439+
reservations[i] = new_reservations(reservations, rq);
440+
create_flow_reservations(rq, &reservations[i], flows[i]);
413441

414-
/* no more than tolerance */
415-
if (!amount_msat_scale(&amt, flow->delivers, tolerance))
416-
continue;
417-
else
418-
can_add = amount_msat_min(can_add, amt);
442+
/* Don't go above our tolerance */
443+
if (amount_msat_greater(capacity, ceiling[i]))
444+
capacity = ceiling[i];
419445

420-
/* no more than max_deliverable */
421-
if (!amount_msat_sub(&amt, flow_max_deliverable(rq, flow, NULL),
422-
flow->delivers))
423-
continue;
446+
if (!amount_msat_sub(&remaining, capacity, flows[i]->delivers))
447+
abort();
448+
if (amount_msat_greater(remaining, best_remaining)) {
449+
best_flownum = i;
450+
best_remaining = remaining;
451+
}
452+
}
453+
tal_free(reservations);
454+
455+
/* Add 1/n of the remainder, or all we can if that's less than 10 sats. */
456+
if (amount_msat_less_sat(shortage, AMOUNT_SAT(10)))
457+
addition = shortage;
424458
else
425-
can_add = amount_msat_min(can_add, amt);
459+
addition = amount_msat_div_ceil(shortage, tal_count(flows));
426460

427-
if (!amount_msat_add(&flow->delivers, flow->delivers,
428-
can_add) ||
429-
!amount_msat_sub(&defect, defect, can_add) ||
430-
!amount_msat_accumulate(&all_deliver, flow->delivers))
461+
/* Can't add it? */
462+
if (amount_msat_less(best_remaining, addition)) {
463+
tal_free(working_ctx);
464+
return false;
465+
}
466+
467+
if (!amount_msat_accumulate(&flows[best_flownum]->delivers, addition))
468+
abort();
469+
if (!amount_msat_deduct(&shortage, addition))
431470
abort();
432471
}
433-
return all_deliver;
472+
tal_free(working_ctx);
473+
return true;
434474
}
435475

436476
const char *refine_flows(const tal_t *ctx, struct route_query *rq,

0 commit comments

Comments
 (0)