Browse Source

mpp: Add the presplit-modifier that splits a root payment first

mpp
Christian Decker 4 years ago
parent
commit
bbb7cb79ab
  1. 7
      lightningd/htlc_set.c
  2. 102
      plugins/libplugin-pay.c
  3. 1
      plugins/libplugin-pay.h

7
lightningd/htlc_set.c

@ -181,6 +181,13 @@ void htlc_set_add(struct lightningd *ld,
return;
}
log_debug(ld->log,
"HTLC set contains %zu HTLCs, for a total of %s out of %s",
tal_count(set->htlcs),
type_to_string(tmpctx, struct amount_msat, &set->so_far),
type_to_string(tmpctx, struct amount_msat, &total_msat)
);
if (amount_msat_eq(set->so_far, total_msat)) {
/* Disable timer now, in case invoice_hook is slow! */
tal_free(set->timeout);

102
plugins/libplugin-pay.c

@ -2047,3 +2047,105 @@ static void waitblockheight_cb(void *d, struct payment *p)
}
REGISTER_PAYMENT_MODIFIER(waitblockheight, void *, NULL, waitblockheight_cb);
/*****************************************************************************
* presplit -- Early MPP splitter modifier.
*
* This splitter modifier is applied to the root payment, and splits the
* payment into parts that are more likely to succeed right away. The
* parameters are derived from probing the network for channel capacities, and
* may be adjusted in future.
*/
/*By probing the capacity from a well-connected vantage point in the network
* we found that the 80th percentile of capacities is >= 9765 sats.
*
* Rounding to 10e6 msats per part there is a ~80% chance that the payment
* will go through without requiring further splitting. The fuzzing is
* symmetric and uniformy distributed around this value, so this should not
* change the success rate much. For the remaining 20% of payments we might
* require a split to make the parts succeed, so we try only a limited number
* of times before we split adaptively.
*
* Notice that these numbers are based on a worst case assumption that
* payments from any node to any other node are equally likely, which isn't
* really the case, so this is likely a lower bound on the success rate.
*
* As the network evolves these numbers are also likely to change.
*/
#define MPP_TARGET_SIZE (10 * 1000 * 1000)
#define MPP_TARGET_MSAT AMOUNT_MSAT(MPP_TARGET_SIZE)
#define MPP_TARGET_FUZZ ( 1 * 1000 * 1000)
static void presplit_cb(void *d, struct payment *p)
{
struct payment *root = payment_root(p);
struct amount_msat amt = root->amount;
if (p->step == PAYMENT_STEP_ONION_PAYLOAD) {
/* We need to tell the last hop the total we're going to
* send. Presplit disables amount fuzzing, so we should always
* get the exact value through. */
size_t lastidx = tal_count(p->createonion_request->hops) - 1;
struct createonion_hop *hop = &p->createonion_request->hops[lastidx];
if (hop->style == ROUTE_HOP_TLV) {
struct tlv_field **fields = &hop->tlv_payload->fields;
tlvstream_set_tlv_payload_data(
fields, root->payment_secret,
root->amount.millisatoshis); /* Raw: onion payload */
}
} else if (p == root && p->step == PAYMENT_STEP_INITIALIZED) {
/* The presplitter only acts on the root and only in the first
* step. */
/* We need to opt-in to the MPP sending facility no matter
* what we do. That means setting all partids to a non-zero
* value. */
root->partid++;
/* If we are already below the target size don't split it
* either. */
if (amount_msat_greater(MPP_TARGET_MSAT, p->amount))
return payment_continue(p);
/* Ok, we know we should split, so split here and then skip this
* payment and start the children instead. */
while (!amount_msat_eq(amt, AMOUNT_MSAT(0))) {
struct payment *c =
payment_new(p, NULL, p, p->modifiers);
/* Pseudorandom number in the range [-1, 1]. */
double rand = pseudorand_double() * 2 - 1;
double multiplier;
c->amount.millisatoshis = rand * MPP_TARGET_FUZZ + MPP_TARGET_SIZE; /* Raw: Multiplication */
/* Clamp the value to the total amount, so the fuzzing
* doesn't go above the total. */
if (amount_msat_greater(c->amount, amt))
c->amount = amt;
multiplier =
(double)c->amount.millisatoshis / (double)p->amount.millisatoshis; /* Raw: msat division. */
if (!amount_msat_sub(&amt, amt, c->amount))
plugin_err(
p->plugin,
"Cannot subtract %s from %s in splitter",
type_to_string(tmpctx, struct amount_msat,
&c->amount),
type_to_string(tmpctx, struct amount_msat,
&amt));
/* Now adjust the constraints so we don't multiply them
* when splitting. */
c->constraints.fee_budget.millisatoshis *= multiplier; /* Raw: Multiplication */
payment_start(c);
}
p->step = PAYMENT_STEP_SPLIT;
}
payment_continue(p);
}
REGISTER_PAYMENT_MODIFIER(presplit, void *, NULL, presplit_cb);

1
plugins/libplugin-pay.h

@ -326,6 +326,7 @@ REGISTER_PAYMENT_MODIFIER_HEADER(exemptfee, struct exemptfee_data);
REGISTER_PAYMENT_MODIFIER_HEADER(shadowroute, struct shadow_route_data);
REGISTER_PAYMENT_MODIFIER_HEADER(directpay, struct direct_pay_data);
extern struct payment_modifier waitblockheight_pay_mod;
extern struct payment_modifier presplit_pay_mod;
/* For the root payment we can seed the channel_hints with the result from
* `listpeers`, hence avoid channels that we know have insufficient capacity

Loading…
Cancel
Save