From 21a06a5cf1718816b1760c9fb2074b2899b13525 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Fri, 10 Jul 2020 14:48:00 +0200 Subject: [PATCH] mpp: Add CLI option to opt-out of multi-part payments Several tests are not well-suited for mpp, so I added a CLI option to opt-out of the MPP support at startup time. --- doc/lightningd-config.5 | 10 +++++++++ doc/lightningd-config.5.md | 8 ++++++++ lightningd/options.c | 3 +++ plugins/libplugin-pay.c | 42 +++++++++++++++++++++++++++++++++----- plugins/libplugin-pay.h | 12 +++++++++-- plugins/libplugin.c | 21 +++++++++++++++++++ plugins/libplugin.h | 2 ++ plugins/pay.c | 10 ++++++++- 8 files changed, 100 insertions(+), 8 deletions(-) diff --git a/doc/lightningd-config.5 b/doc/lightningd-config.5 index 18432a18a..cb18a1b51 100644 --- a/doc/lightningd-config.5 +++ b/doc/lightningd-config.5 @@ -378,6 +378,16 @@ up space in the database\. Control how long invoices must have been expired before they are cleaned (if \fIautocleaninvoice-cycle\fR is non-zero)\. + +Payment control options: + + + \fBdisable-mpp\fR +Disable the multi-part payment sending support in the \fBpay\fR plugin\. By default +the MPP support is enabled, but it can be desirable to disable in situations +in which each payment should result in a single HTLC being forwarded in the +network\. + .SH Networking options Note that for simple setups, the implicit \fIautolisten\fR option does the diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index 2bdfc1473..39122ec9d 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -309,6 +309,14 @@ up space in the database. Control how long invoices must have been expired before they are cleaned (if *autocleaninvoice-cycle* is non-zero). +Payment control options: + + **disable-mpp** +Disable the multi-part payment sending support in the `pay` plugin. By default +the MPP support is enabled, but it can be desirable to disable in situations +in which each payment should result in a single HTLC being forwarded in the +network. + ### Networking options Note that for simple setups, the implicit *autolisten* option does the diff --git a/lightningd/options.c b/lightningd/options.c index c46f89ffd..444670b2a 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -1201,6 +1201,9 @@ static void add_config(struct lightningd *ld, feature_offered(ld->our_features ->bits[INIT_FEATURE], OPT_LARGE_CHANNELS)); + } else if (opt->cb == (void *)plugin_opt_flag_set) { + /* Noop, they will get added below along with the + * OPT_HASARG options. */ } else { /* Insert more decodes here! */ assert(!"A noarg option was added but was not handled"); diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 17a127d83..c10925f22 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -2082,11 +2082,26 @@ REGISTER_PAYMENT_MODIFIER(waitblockheight, void *, NULL, waitblockheight_cb); #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) +static struct presplit_mod_data *presplit_mod_data_init(struct payment *p) +{ + struct presplit_mod_data *d; + if (p->parent == NULL) { + d = tal(p, struct presplit_mod_data); + d->disable = false; + return d; + } else { + return payment_mod_presplit_get_data(p->parent); + } +} + +static void presplit_cb(struct presplit_mod_data *d, struct payment *p) { struct payment *root = payment_root(p); struct amount_msat amt = root->amount; + if (d->disable) + return payment_continue(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 @@ -2166,7 +2181,8 @@ static void presplit_cb(void *d, struct payment *p) payment_continue(p); } -REGISTER_PAYMENT_MODIFIER(presplit, void *, NULL, presplit_cb); +REGISTER_PAYMENT_MODIFIER(presplit, struct presplit_mod_data *, + presplit_mod_data_init, presplit_cb); /***************************************************************************** * Adaptive splitter -- Split payment if we can't get it through. @@ -2179,9 +2195,25 @@ REGISTER_PAYMENT_MODIFIER(presplit, void *, NULL, presplit_cb); #define MPP_ADAPTIVE_LOWER_LIMIT AMOUNT_MSAT(100 * 1000) -static void adaptive_splitter_cb(void *d, struct payment *p) +static struct presplit_mod_data *adaptive_splitter_data_init(struct payment *p) +{ + struct presplit_mod_data *d; + if (p->parent == NULL) { + d = tal(p, struct presplit_mod_data); + d->disable = false; + return d; + } else { + return payment_mod_presplit_get_data(p->parent); + } +} + +static void adaptive_splitter_cb(struct presplit_mod_data *d, struct payment *p) { struct payment *root = payment_root(p); + + if (d->disable) + return payment_continue(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 @@ -2236,5 +2268,5 @@ static void adaptive_splitter_cb(void *d, struct payment *p) payment_continue(p); } -REGISTER_PAYMENT_MODIFIER(adaptive_splitter, void *, NULL, - adaptive_splitter_cb); +REGISTER_PAYMENT_MODIFIER(adaptive_splitter, struct presplit_mod_data *, + adaptive_splitter_data_init, adaptive_splitter_cb); diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index 3851bac6e..7c52173d6 100644 --- a/plugins/libplugin-pay.h +++ b/plugins/libplugin-pay.h @@ -319,6 +319,14 @@ struct direct_pay_data { * attempt against the channel hints. */ 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 { + bool disable; +}; + /* List of globally available payment modifiers. */ REGISTER_PAYMENT_MODIFIER_HEADER(retry, struct retry_mod_data); REGISTER_PAYMENT_MODIFIER_HEADER(routehints, struct routehints_data); @@ -326,8 +334,8 @@ 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; -extern struct payment_modifier adaptive_splitter_pay_mod; +REGISTER_PAYMENT_MODIFIER_HEADER(presplit, struct presplit_mod_data); +REGISTER_PAYMENT_MODIFIER_HEADER(adaptive_splitter, struct presplit_mod_data); /* For the root payment we can seed the channel_hints with the result from * `listpeers`, hence avoid channels that we know have insufficient capacity diff --git a/plugins/libplugin.c b/plugins/libplugin.c index b5c8b0bf1..c5c5500a6 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -862,6 +862,27 @@ char *u32_option(const char *arg, u32 *i) return NULL; } +char *bool_option(const char *arg, bool *i) +{ + if (!streq(arg, "true") && !streq(arg, "false")) + return tal_fmt(NULL, "'%s' is not a bool, must be \"true\" or \"false\"", arg); + + *i = streq(arg, "true"); + return NULL; +} + +char *flag_option(const char *arg, bool *i) +{ + /* We only get called if the flag was provided, so *i should be false + * by default */ + assert(*i == false); + if (!streq(arg, "true")) + return tal_fmt(NULL, "Invalid argument '%s' passed to a flag", arg); + + *i = true; + return NULL; +} + char *charp_option(const char *arg, char **p) { *p = tal_strdup(NULL, arg); diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 85711bda9..bc1e2ac21 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -239,7 +239,9 @@ void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...) PRINTF /* Standard helpers */ char *u64_option(const char *arg, u64 *i); char *u32_option(const char *arg, u32 *i); +char *bool_option(const char *arg, bool *i); char *charp_option(const char *arg, char **p); +char *flag_option(const char *arg, bool *i); /* The main plugin runner: append with 0 or more plugin_option(), then NULL. */ void NORETURN LAST_ARG_NULL plugin_main(char *argv[], diff --git a/plugins/pay.c b/plugins/pay.c index 5d3068245..a6002c481 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -25,6 +25,8 @@ /* Public key of this node. */ static struct node_id my_id; static unsigned int maxdelay_default; +static bool disablempp = false; + static LIST_HEAD(pay_status); static LIST_HEAD(payments); @@ -1955,6 +1957,8 @@ static struct command_result *json_paymod(struct command *cmd, payment_mod_exemptfee_get_data(p)->amount = *exemptfee; shadow_route = payment_mod_shadowroute_get_data(p); + payment_mod_presplit_get_data(p)->disable = disablempp; + payment_mod_adaptive_splitter_get_data(p)->disable = disablempp; /* This is an MPP enabled pay command, disable amount fuzzing. */ shadow_route->fuzz_amount = false; @@ -2004,5 +2008,9 @@ int main(int argc, char *argv[]) { setup_locale(); plugin_main(argv, init, PLUGIN_RESTARTABLE, NULL, commands, - ARRAY_SIZE(commands), NULL, 0, NULL, 0, NULL); + ARRAY_SIZE(commands), NULL, 0, NULL, 0, + plugin_option("disable-mpp", "flag", + "Disable multi-part payments.", + flag_option, &disablempp), + NULL); }