mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 13:25:43 +01:00
paymod: Implement adaptive splitter
This modifier splits a payment that has been attempted a number of times (by a modifier earlier in the mod chain) and has failed consistently. It splits the amount roughly in half, with a but if random fuzz, and then starts a new round of attempts for the two smaller amounts.
This commit is contained in:
parent
443643e0b0
commit
535aaca109
@ -2167,3 +2167,74 @@ static void presplit_cb(void *d, struct payment *p)
|
||||
}
|
||||
|
||||
REGISTER_PAYMENT_MODIFIER(presplit, void *, NULL, presplit_cb);
|
||||
|
||||
/*****************************************************************************
|
||||
* Adaptive splitter -- Split payment if we can't get it through.
|
||||
*
|
||||
* The adaptive splitter splits the amount of a failed payment in half, with
|
||||
* +/- 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
|
||||
* constraints, but that can complete the payment.
|
||||
*/
|
||||
|
||||
#define MPP_ADAPTIVE_LOWER_LIMIT AMOUNT_MSAT(100 * 1000)
|
||||
|
||||
static void adaptive_splitter_cb(void *d, struct payment *p)
|
||||
{
|
||||
struct payment *root = payment_root(p);
|
||||
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->step == PAYMENT_STEP_FAILED && !p->abort) {
|
||||
if (amount_msat_greater(p->amount, MPP_ADAPTIVE_LOWER_LIMIT)) {
|
||||
struct payment *a, *b;
|
||||
/* Random number in the range [90%, 110%] */
|
||||
double rand = pseudorand_double() * 0.2 + 0.9;
|
||||
u64 mid = p->amount.millisatoshis / 2 * rand; /* Raw: multiplication */
|
||||
bool ok;
|
||||
|
||||
a = payment_new(p, NULL, p, p->modifiers);
|
||||
b = payment_new(p, NULL, p, p->modifiers);
|
||||
|
||||
a->amount.millisatoshis = mid; /* Raw: split. */
|
||||
b->amount.millisatoshis -= mid; /* Raw: split. */
|
||||
|
||||
/* Adjust constraints since we don't want to double our
|
||||
* fee allowance when we split. */
|
||||
a->constraints.fee_budget.millisatoshis *= (double)a->amount.millisatoshis / (double)p->amount.millisatoshis; /* Raw: msat division. */
|
||||
ok = amount_msat_sub(&b->constraints.fee_budget,
|
||||
p->constraints.fee_budget,
|
||||
a->constraints.fee_budget);
|
||||
|
||||
/* Should not fail, mid is less than 55% of original
|
||||
* amount. fee_budget_a <= 55% of fee_budget_p (parent
|
||||
* of the new payments).*/
|
||||
assert(ok);
|
||||
|
||||
payment_start(a);
|
||||
payment_start(b);
|
||||
p->step = PAYMENT_STEP_SPLIT;
|
||||
} else {
|
||||
plugin_log(p->plugin, LOG_INFORM,
|
||||
"Lower limit of adaptive splitter reached "
|
||||
"(%s < %s), not splitting further.",
|
||||
type_to_string(tmpctx, struct amount_msat,
|
||||
&p->amount),
|
||||
type_to_string(tmpctx, struct amount_msat,
|
||||
&MPP_ADAPTIVE_LOWER_LIMIT));
|
||||
}
|
||||
}
|
||||
payment_continue(p);
|
||||
}
|
||||
|
||||
REGISTER_PAYMENT_MODIFIER(adaptive_splitter, void *, NULL,
|
||||
adaptive_splitter_cb);
|
||||
|
@ -327,6 +327,7 @@ 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;
|
||||
extern struct payment_modifier adaptive_splitter_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…
Reference in New Issue
Block a user