Browse Source

paymod: Teach the adaptive splitter to respect the HTLC limit

There is little point in trying to split if the resulting HTLCs exceed the
maximum number of HTLCs we can add to our channels. So abort if a split would
result in more HTLCs than our channels can support.
route-mem-overrun
Christian Decker 5 years ago
committed by Rusty Russell
parent
commit
e92787a0e2
  1. 52
      plugins/libplugin-pay.c
  2. 10
      plugins/libplugin-pay.h

52
plugins/libplugin-pay.c

@ -2537,32 +2537,56 @@ REGISTER_PAYMENT_MODIFIER(presplit, struct presplit_mod_data *,
* +/- 10% randomness, and then starts two attempts, one for either side of * +/- 10% randomness, and then starts two attempts, one for either side of
* the split. The goal is to find two smaller routes, that still adhere to our * the split. The goal is to find two smaller routes, that still adhere to our
* constraints, but that can complete the payment. * constraints, but that can complete the payment.
*
* This modifier also checks whether we can split and still have enough HTLCs
* available on the channels and aborts if that's no longer the case.
*/ */
#define MPP_ADAPTIVE_LOWER_LIMIT AMOUNT_MSAT(100 * 1000) #define MPP_ADAPTIVE_LOWER_LIMIT AMOUNT_MSAT(100 * 1000)
static struct presplit_mod_data *adaptive_splitter_data_init(struct payment *p) static struct adaptive_split_mod_data *adaptive_splitter_data_init(struct payment *p)
{ {
struct presplit_mod_data *d; struct adaptive_split_mod_data *d;
if (p->parent == NULL) { if (p->parent == NULL) {
d = tal(p, struct presplit_mod_data); d = tal(p, struct adaptive_split_mod_data);
d->disable = false; d->disable = false;
d->htlc_budget = 0;
return d; return d;
} else { } else {
return payment_mod_presplit_get_data(p->parent); return payment_mod_adaptive_splitter_get_data(p->parent);
} }
} }
static void adaptive_splitter_cb(struct presplit_mod_data *d, struct payment *p) static void adaptive_splitter_cb(struct adaptive_split_mod_data *d, struct payment *p)
{ {
struct payment *root = payment_root(p); struct payment *root = payment_root(p);
struct adaptive_split_mod_data *root_data =
payment_mod_adaptive_splitter_get_data(root);
if (d->disable) if (d->disable)
return payment_continue(p); return payment_continue(p);
if (!payment_supports_mpp(p) || root->abort) if (!payment_supports_mpp(p) || root->abort)
return payment_continue(p); return payment_continue(p);
if (p->parent == NULL && d->htlc_budget == 0) {
/* Now that we potentially had an early splitter run, let's
* update our htlc_budget that we own exclusively from now
* on. We do this by subtracting the number of payment
* attempts an eventual presplitter has already performed. */
struct payment_tree_result res;
res = payment_collect_result(p);
d->htlc_budget = payment_max_htlcs(p);
if (res.attempts > d->htlc_budget) {
p->abort = true;
return payment_fail(
p,
"Cannot add %d HTLCs to our channels, we "
"only have %d HTLCs available.",
res.attempts, d->htlc_budget);
}
d->htlc_budget -= res.attempts;
}
if (p->step == PAYMENT_STEP_ONION_PAYLOAD) { if (p->step == PAYMENT_STEP_ONION_PAYLOAD) {
/* We need to tell the last hop the total we're going to /* We need to tell the last hop the total we're going to
* send. Presplit disables amount fuzzing, so we should always * send. Presplit disables amount fuzzing, so we should always
@ -2585,6 +2609,16 @@ static void adaptive_splitter_cb(struct presplit_mod_data *d, struct payment *p)
/* Use the start constraints, not the ones updated by routes and shadow-routes. */ /* Use the start constraints, not the ones updated by routes and shadow-routes. */
struct payment_constraints *pconstraints = p->start_constraints; struct payment_constraints *pconstraints = p->start_constraints;
/* First check that splitting doesn't exceed our HTLC budget */
if (root_data->htlc_budget == 0) {
root->abort = true;
return payment_fail(
p,
"Cannot split payment any further without "
"exceeding the maximum number of HTLCs "
"allowed by our channels");
}
a = payment_new(p, NULL, p, p->modifiers); a = payment_new(p, NULL, p, p->modifiers);
b = payment_new(p, NULL, p, p->modifiers); b = payment_new(p, NULL, p, p->modifiers);
@ -2610,6 +2644,10 @@ static void adaptive_splitter_cb(struct presplit_mod_data *d, struct payment *p)
payment_start(a); payment_start(a);
payment_start(b); payment_start(b);
p->step = PAYMENT_STEP_SPLIT; p->step = PAYMENT_STEP_SPLIT;
/* Take note that we now have an additional split that
* may end up using an HTLC. */
root_data->htlc_budget--;
} else { } else {
plugin_log(p->plugin, LOG_INFORM, plugin_log(p->plugin, LOG_INFORM,
"Lower limit of adaptive splitter reached " "Lower limit of adaptive splitter reached "
@ -2623,5 +2661,5 @@ static void adaptive_splitter_cb(struct presplit_mod_data *d, struct payment *p)
payment_continue(p); payment_continue(p);
} }
REGISTER_PAYMENT_MODIFIER(adaptive_splitter, struct presplit_mod_data *, REGISTER_PAYMENT_MODIFIER(adaptive_splitter, struct adaptive_split_mod_data *,
adaptive_splitter_data_init, adaptive_splitter_cb); adaptive_splitter_data_init, adaptive_splitter_cb);

10
plugins/libplugin-pay.h

@ -328,13 +328,15 @@ struct direct_pay_data {
struct short_channel_id_dir *chan; struct short_channel_id_dir *chan;
}; };
/* Since presplit and adaptive mpp modifiers share the same information we
* just use the same backing struct. Should they deviate we can create an
* adaptive_splitter_mod_data struct and populate that. */
struct presplit_mod_data { struct presplit_mod_data {
bool disable; bool disable;
}; };
struct adaptive_split_mod_data {
bool disable;
u32 htlc_budget;
};
/* List of globally available payment modifiers. */ /* List of globally available payment modifiers. */
REGISTER_PAYMENT_MODIFIER_HEADER(retry, struct retry_mod_data); REGISTER_PAYMENT_MODIFIER_HEADER(retry, struct retry_mod_data);
REGISTER_PAYMENT_MODIFIER_HEADER(routehints, struct routehints_data); REGISTER_PAYMENT_MODIFIER_HEADER(routehints, struct routehints_data);
@ -343,7 +345,7 @@ REGISTER_PAYMENT_MODIFIER_HEADER(shadowroute, struct shadow_route_data);
REGISTER_PAYMENT_MODIFIER_HEADER(directpay, struct direct_pay_data); REGISTER_PAYMENT_MODIFIER_HEADER(directpay, struct direct_pay_data);
extern struct payment_modifier waitblockheight_pay_mod; extern struct payment_modifier waitblockheight_pay_mod;
REGISTER_PAYMENT_MODIFIER_HEADER(presplit, struct presplit_mod_data); REGISTER_PAYMENT_MODIFIER_HEADER(presplit, struct presplit_mod_data);
REGISTER_PAYMENT_MODIFIER_HEADER(adaptive_splitter, struct presplit_mod_data); REGISTER_PAYMENT_MODIFIER_HEADER(adaptive_splitter, struct adaptive_split_mod_data);
/* For the root payment we can seed the channel_hints with the result from /* For the root payment we can seed the channel_hints with the result from
* `listpeers`, hence avoid channels that we know have insufficient capacity * `listpeers`, hence avoid channels that we know have insufficient capacity

Loading…
Cancel
Save