mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
pay: Add a pre-apply check to channel_hint updates
This allows us to atomically update all channel_hints and determine if we had a collision and therefore should retry.
This commit is contained in:
committed by
Rusty Russell
parent
83f57ac300
commit
544e110c96
@@ -444,6 +444,21 @@ payment_constraints_update(struct payment_constraints *cons,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct channel_hint *payment_chanhints_get(struct payment *p,
|
||||||
|
struct route_hop *h)
|
||||||
|
{
|
||||||
|
struct payment *root = payment_root(p);
|
||||||
|
struct channel_hint *curhint;
|
||||||
|
for (size_t j = 0; j < tal_count(root->channel_hints); j++) {
|
||||||
|
curhint = &root->channel_hints[j];
|
||||||
|
if (short_channel_id_eq(&curhint->scid.scid, &h->channel_id) &&
|
||||||
|
curhint->scid.dir == h->direction) {
|
||||||
|
return curhint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Given a route and a couple of channel hints, apply the route to the channel
|
/* Given a route and a couple of channel hints, apply the route to the channel
|
||||||
* hints, so we have a better estimation of channel's capacity. We apply a
|
* hints, so we have a better estimation of channel's capacity. We apply a
|
||||||
* route to a channel hint before calling `sendonion` so subsequent `route`
|
* route to a channel hint before calling `sendonion` so subsequent `route`
|
||||||
@@ -453,19 +468,55 @@ payment_constraints_update(struct payment_constraints *cons,
|
|||||||
* through, since the balances really changed in that case. The `remove`
|
* through, since the balances really changed in that case. The `remove`
|
||||||
* argument indicates whether we want to apply (`remove=false`), or clear a
|
* argument indicates whether we want to apply (`remove=false`), or clear a
|
||||||
* prior application (`remove=true`). */
|
* prior application (`remove=true`). */
|
||||||
static void payment_chanhints_apply_route(struct payment *p, bool remove)
|
static bool payment_chanhints_apply_route(struct payment *p, bool remove)
|
||||||
{
|
{
|
||||||
struct route_hop *curhop;
|
struct route_hop *curhop;
|
||||||
struct channel_hint *curhint;
|
struct channel_hint *curhint;
|
||||||
struct payment *root = payment_root(p);
|
struct payment *root = payment_root(p);
|
||||||
assert(p->route != NULL);
|
assert(p->route != NULL);
|
||||||
|
|
||||||
|
/* No need to check for applicability if we increase
|
||||||
|
* capacity and budgets. */
|
||||||
|
if (remove)
|
||||||
|
goto apply_changes;
|
||||||
|
|
||||||
|
/* First round: make sure we can cleanly apply the update. */
|
||||||
for (size_t i = 0; i < tal_count(p->route); i++) {
|
for (size_t i = 0; i < tal_count(p->route); i++) {
|
||||||
curhop = &p->route[i];
|
curhop = &p->route[i];
|
||||||
for (size_t j = 0; j < tal_count(root->channel_hints); j++) {
|
curhint = payment_chanhints_get(root, curhop);
|
||||||
curhint = &root->channel_hints[j];
|
|
||||||
if (short_channel_id_eq(&curhint->scid.scid,
|
/* If we don't have a hint we can't fail updating it. */
|
||||||
&curhop->channel_id) &&
|
if (!curhint)
|
||||||
curhint->scid.dir == curhop->direction) {
|
continue;
|
||||||
|
|
||||||
|
/* A failure can happen if we add an HTLC, and either
|
||||||
|
* the local htlc_budget is exhausted, or the capacity
|
||||||
|
* is exceeded. */
|
||||||
|
if ((curhint->local && curhint->htlc_budget <= 0) ||
|
||||||
|
amount_msat_greater(curhop->amount,
|
||||||
|
curhint->estimated_capacity)) {
|
||||||
|
/* This can happen in case of multiple
|
||||||
|
* concurrent getroute calls using the
|
||||||
|
* same channel_hints, no biggy, it's
|
||||||
|
* an estimation anyway. */
|
||||||
|
paymod_log(p, LOG_DBG,
|
||||||
|
"Could not update the channel hint "
|
||||||
|
"for %s. Could be a concurrent "
|
||||||
|
"`getroute` call.",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct short_channel_id_dir,
|
||||||
|
&curhint->scid));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_changes:
|
||||||
|
/* Second round: apply the changes, now that we know they'll succeed. */
|
||||||
|
for (size_t i = 0; i < tal_count(p->route); i++) {
|
||||||
|
curhop = &p->route[i];
|
||||||
|
curhint = payment_chanhints_get(root, curhop);
|
||||||
|
if (!curhint)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Update the number of htlcs for any local
|
/* Update the number of htlcs for any local
|
||||||
* channel in the route */
|
* channel in the route */
|
||||||
@@ -487,23 +538,13 @@ static void payment_chanhints_apply_route(struct payment *p, bool remove)
|
|||||||
&curhint->estimated_capacity,
|
&curhint->estimated_capacity,
|
||||||
curhint->estimated_capacity,
|
curhint->estimated_capacity,
|
||||||
curhop->amount)) {
|
curhop->amount)) {
|
||||||
/* This can happen in case of multipl
|
/* Given our preemptive test
|
||||||
* concurrent getroute calls using the
|
* above, this should never
|
||||||
* same channel_hints, no biggy, it's
|
* happen either. */
|
||||||
* an estimation anyway. */
|
abort();
|
||||||
paymod_log(
|
|
||||||
p, LOG_UNUSUAL,
|
|
||||||
"Could not update the channel hint "
|
|
||||||
"for %s. Could be a concurrent "
|
|
||||||
"`getroute` call.",
|
|
||||||
type_to_string(
|
|
||||||
tmpctx,
|
|
||||||
struct short_channel_id_dir,
|
|
||||||
&curhint->scid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct short_channel_id_dir *
|
static const struct short_channel_id_dir *
|
||||||
|
|||||||
Reference in New Issue
Block a user