Skip to content

Commit 78451e6

Browse files
cdeckerrustyrussell
authored andcommitted
pay: Add a hysteresis for channel_hint relaxation
If we have a large channel, fail to send through a small amount, and then add a `channel_hint`, then it can happen that the call to `channel_hint_set_update` is already late enough that it refills the 1msat we removed from the attempted amount, thus making the edge we just excluded eligible again, which can lead into an infinite loop. We slow down the updating of the channel_hints to once every hysteresis timeout. This allows us to set tight constraints, while not incurring in the accidental relaxation issue.
1 parent e3c0a36 commit 78451e6

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

plugins/channel_hint.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,27 @@ void channel_hint_to_json(const char *name, const struct channel_hint *hint,
1414
json_object_end(dest);
1515
}
1616

17+
/* How long until even a channel whose estimate is down at 0msat will
18+
* be considered fully refilled. The refill rate is the inverse of
19+
* this times the channel size. The refilling is a linear
20+
* approximation, with a small hysteresis applied in order to prevent
21+
* a single payment relaxing its own constraints thus causing it to
22+
* prematurely retry an already attempted channel.
23+
*/
1724
#define PAY_REFILL_TIME 7200
1825

26+
/* Add an artificial delay before accepting updates. This ensures we
27+
* don't actually end up relaxing a tight constraint inbetween the
28+
* attempt that added it and the next retry. If we were to relax right
29+
* away, then we could end up retrying the exact same path we just
30+
* failed at. If the `time_between_attempts * refill > 1msat`, we'd
31+
* end up not actually constraining at all, because we set the
32+
* estimate to `attempt - 1msat`. This also results in the updates
33+
* being limited to once every minute, and causes a stairway
34+
* pattern. The hysteresis has to be >60s otherwise a single payment
35+
* can already end up retrying a previously excluded channel.
36+
*/
37+
#define PAY_REFILL_HYSTERESIS 60
1938
/**
2039
* Update the `channel_hint` in place, return whether it should be kept.
2140
*
@@ -40,6 +59,9 @@ bool channel_hint_update(const struct timeabs now, struct channel_hint *hint)
4059
if (!amount_sat_to_msat(&capacity, hint->capacity))
4160
abort();
4261

62+
if (now.ts.tv_sec < hint->timestamp + PAY_REFILL_HYSTERESIS)
63+
return true;
64+
4365
u64 seconds = now.ts.tv_sec - hint->timestamp;
4466
if (!amount_msat_mul(&refill, capacity, seconds))
4567
abort();

0 commit comments

Comments
 (0)