From c97ff05ffb4b4d898cf333b93dde249a306e018d Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Wed, 1 Jul 2020 18:59:42 +0200 Subject: [PATCH] mpp: Add the presplit-modifier that splits a root payment first --- lightningd/htlc_set.c | 7 +++ plugins/libplugin-pay.c | 102 ++++++++++++++++++++++++++++++++++++++++ plugins/libplugin-pay.h | 1 + 3 files changed, 110 insertions(+) diff --git a/lightningd/htlc_set.c b/lightningd/htlc_set.c index 1bcb4e1f2..050255fe1 100644 --- a/lightningd/htlc_set.c +++ b/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); diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index db8a55c0f..c9622b572 100644 --- a/plugins/libplugin-pay.c +++ b/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); diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index fa7db3907..7cbb4a4be 100644 --- a/plugins/libplugin-pay.h +++ b/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