Browse Source

paymod: Add a simple test-command to test the paymod state-machine

This commit can be reverted/skipped once we have implemented all the logic and
have feature parity with the normal `pay`. It's main purpose is to expose the
unfinished functionality to test it, without completely breaking the existing
`pay` command.
paymod-02
Christian Decker 5 years ago
parent
commit
23b4dca3c7
  1. 17
      plugins/libplugin-pay.c
  2. 4
      plugins/libplugin-pay.h
  3. 76
      plugins/pay.c
  4. 14
      tests/test_pay.py

17
plugins/libplugin-pay.c

@ -1,4 +1,5 @@
#include <plugins/libplugin-pay.h>
#include <stdio.h>
struct payment *payment_new(tal_t *ctx, struct command *cmd,
struct payment *parent,
@ -144,3 +145,19 @@ void payment_continue(struct payment *p)
* `payment_continue` after the final state. */
abort();
}
static inline struct dummy_data *
dummy_data_init(struct payment *p)
{
return tal(p, struct dummy_data);
}
static inline void dummy_step_cb(struct dummy_data *dd,
struct payment *p)
{
fprintf(stderr, "dummy_step_cb called for payment %p at step %d\n", p, p->step);
payment_continue(p);
}
REGISTER_PAYMENT_MODIFIER(dummy, struct dummy_data *, dummy_data_init,
dummy_step_cb);

4
plugins/libplugin-pay.h

@ -129,6 +129,10 @@ struct payment_modifier {
void (*)(data_type, struct payment *), step_cb), \
};
struct dummy_data {
unsigned int *dummy_param;
};
/* List of globally available payment modifiers. */
extern struct payment_modifier dummy_pay_mod;

76
plugins/pay.c

@ -15,6 +15,7 @@
#include <common/pseudorand.h>
#include <common/type_to_string.h>
#include <inttypes.h>
#include <plugins/libplugin-pay.h>
#include <plugins/libplugin.h>
#include <stdint.h>
#include <stdio.h>
@ -1702,6 +1703,70 @@ static void init(struct plugin *p,
maxdelay_default = atoi(field);
}
#if DEVELOPER
struct payment_modifier *paymod_mods[2] = {
&dummy_pay_mod,
NULL,
};
static struct command_result *json_paymod(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
struct payment *p;
const char *b11str;
struct bolt11 *b11;
char *fail;
struct dummy_data *ddata;
p = payment_new(cmd, cmd, NULL /* No parent */, paymod_mods);
ddata = (struct dummy_data*)p->modifier_data[0];
/* If any of the modifiers need to add params to the JSON-RPC call we
* would add them to the `param()` call below, and have them be
* initialized directly that way. */
if (!param(cmd, buf, params, p_req("bolt11", param_string, &b11str),
p_opt_def("dummy", param_number, &ddata->dummy_param, 42),
NULL))
return command_param_failed();
b11 = bolt11_decode(cmd, b11str, plugin_feature_set(cmd->plugin),
NULL, &fail);
if (!b11)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail);
if (!b11->chain)
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "Invoice is for an unknown network");
if (b11->chain != chainparams)
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "Invoice is for another network %s", b11->chain->network_name);
if (time_now().ts.tv_sec > b11->timestamp + b11->expiry)
return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired");
if (b11->msat)
p->amount = *b11->msat;
else
abort();
/* Sanity check */
if (feature_offered(b11->features, OPT_VAR_ONION)
&& !b11->payment_secret)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11:"
" sets feature var_onion with no secret");
p->json_buffer = tal_steal(p, buf);
p->json_toks = params;
p->destination = p->getroute_destination = &b11->receiver_id;
p->payment_hash = tal_dup(p, struct sha256, &b11->payment_hash);
payment_start(p);
return command_still_pending(cmd);
}
#endif
static const struct plugin_command commands[] = { {
"pay",
"payment",
@ -1720,7 +1785,16 @@ static const struct plugin_command commands[] = { {
"List result of payment {bolt11}, or all",
"Covers old payments (failed and succeeded) and current ones.",
json_listpays
}
},
#if DEVELOPER
{
"paymod",
"payment",
"Send payment specified by {bolt11}",
"Experimental implementation of pay using modifiers",
json_paymod
},
#endif
};
int main(int argc, char *argv[])

14
tests/test_pay.py

@ -3043,3 +3043,17 @@ def test_invalid_onion_channel_update(node_factory):
# l1 should still be alive afterwards.
assert l1.rpc.getinfo()['id'] == l1id
@unittest.skipIf(not DEVELOPER, "paymod is only available to developers for now.")
def test_pay_modifiers(node_factory):
l1, l2 = node_factory.line_graph(2, opts=[{}, {}])
# Make sure that the dummy param is in the help (and therefore assigned to
# the modifier data).
hlp = l1.rpc.help("paymod")['help'][0]
assert(hlp['command'] == 'paymod bolt11 [dummy]')
inv = l2.rpc.invoice(123, 'lbl', 'desc')['bolt11']
with pytest.raises(RpcError, match="Not functional yet"):
l1.rpc.paymod(inv)

Loading…
Cancel
Save