mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-22 08:34:20 +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:
@@ -2167,3 +2167,74 @@ static void presplit_cb(void *d, struct payment *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_PAYMENT_MODIFIER(presplit, void *, NULL, presplit_cb);
|
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);
|
REGISTER_PAYMENT_MODIFIER_HEADER(directpay, struct direct_pay_data);
|
||||||
extern struct payment_modifier waitblockheight_pay_mod;
|
extern struct payment_modifier waitblockheight_pay_mod;
|
||||||
extern struct payment_modifier presplit_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
|
/* 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
|
||||||
|
|||||||
Reference in New Issue
Block a user