diff --git a/contrib/pylightning/lightning/lightning.py b/contrib/pylightning/lightning/lightning.py index 434fbc0234f3..9e7e45465220 100644 --- a/contrib/pylightning/lightning/lightning.py +++ b/contrib/pylightning/lightning/lightning.py @@ -434,6 +434,28 @@ def dev_memleak(self): """ return self.call("dev-memleak") + def dev_pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, + description=None, maxfeepercent=None, retry_for=None, + maxdelay=None, exemptfee=None, use_shadow=True): + """ + A developer version of `pay`, with the possibility to deactivate + shadow routing (used for testing). + """ + payload = { + "bolt11": bolt11, + "msatoshi": msatoshi, + "label": label, + "riskfactor": riskfactor, + "maxfeepercent": maxfeepercent, + "retry_for": retry_for, + "maxdelay": maxdelay, + "exemptfee": exemptfee, + "use_shadow": use_shadow, + # Deprecated. + "description": description, + } + return self.call("pay", payload) + def dev_reenable_commit(self, peer_id): """ Re-enable the commit timer on peer {id} @@ -761,7 +783,9 @@ def newaddr(self, addresstype=None): """ return self.call("newaddr", {"addresstype": addresstype}) - def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, description=None): + def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, + description=None, maxfeepercent=None, retry_for=None, + maxdelay=None, exemptfee=None): """ Send payment specified by {bolt11} with {msatoshi} (ignored if {bolt11} has an amount), optional {label} @@ -772,6 +796,10 @@ def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, description=No "msatoshi": msatoshi, "label": label, "riskfactor": riskfactor, + "maxfeepercent": maxfeepercent, + "retry_for": retry_for, + "maxdelay": maxdelay, + "exemptfee": exemptfee, # Deprecated. "description": description, } diff --git a/plugins/pay.c b/plugins/pay.c index fc3e2dd155d2..3819fd524828 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -103,6 +103,11 @@ struct pay_command { /* Any remaining routehints to try. */ struct route_info **routehints; +#if DEVELOPER + /* Disable the use of shadow route ? */ + double use_shadow; +#endif + /* Current node during shadow route calculation. */ const char *shadow_dest; }; @@ -873,6 +878,10 @@ static struct command_result *add_shadow_route(struct command *cmd, static struct command_result *shadow_route(struct command *cmd, struct pay_command *pc) { +#if DEVELOPER + if (!pc->use_shadow) + return start_pay_attempt(cmd, pc, "Initial attempt"); +#endif if (pseudorand(2) == 0) return start_pay_attempt(cmd, pc, "Initial attempt"); @@ -1034,6 +1043,9 @@ static struct command_result *json_pay(struct command *cmd, double *maxfeepercent; unsigned int *maxdelay; struct amount_msat *exemptfee; +#if DEVELOPER + bool *use_shadow; +#endif if (!param(cmd, buf, params, p_req("bolt11", param_string, &b11str), @@ -1045,6 +1057,9 @@ static struct command_result *json_pay(struct command *cmd, p_opt_def("maxdelay", param_number, &maxdelay, maxdelay_default), p_opt_def("exemptfee", param_msat, &exemptfee, AMOUNT_MSAT(5000)), +#if DEVELOPER + p_opt_def("use_shadow", param_bool, &use_shadow, true), +#endif NULL)) return command_param_failed(); @@ -1096,6 +1111,9 @@ static struct command_result *json_pay(struct command *cmd, pc->current_routehint = NULL; pc->routehints = filter_routehints(pc, b11->routes); pc->expensive_route = NULL; +#if DEVELOPER + pc->use_shadow = *use_shadow; +#endif /* Get capacities of local channels (no parameters) */ return send_outreq(cmd, "listpeers", listpeers_done, forward_error, pc, diff --git a/tests/test_plugin.py b/tests/test_plugin.py index b1e6ef84cb84..a406451c18fb 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -239,8 +239,11 @@ def test_pay_plugin(node_factory): l1.rpc.call('pay') # Make sure usage messages are present. - assert only_one(l1.rpc.help('pay')['help'])['command'] == 'pay bolt11 [msatoshi] [label] [riskfactor] [maxfeepercent] [retry_for] [maxdelay] [exemptfee]' - assert only_one(l1.rpc.help('paystatus')['help'])['command'] == 'paystatus [bolt11]' + msg = 'pay bolt11 [msatoshi] [label] [riskfactor] [maxfeepercent] '\ + '[retry_for] [maxdelay] [exemptfee]' + if DEVELOPER: + msg += ' [use_shadow]' + assert only_one(l1.rpc.help('pay')['help'])['command'] == msg def test_plugin_connected_hook(node_factory):