From 2bff80e3dea1ce2a739bfcf0d74c9bb8def016e2 Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 30 Jan 2020 00:55:55 +0100 Subject: [PATCH] libplugin: use json_stream helpers for RPC calls This adds helpers to start and send a jsonrpc request using json_stream in order to benefit from the helpers. This then simplifies existing plugins RPC requests by using json_stream helpers. --- plugins/autoclean.c | 15 ++-- plugins/fundchannel.c | 192 ++++++++++++++++-------------------------- plugins/libplugin.c | 94 +++++++++------------ plugins/libplugin.h | 82 +++++++++++------- plugins/pay.c | 124 +++++++++++++-------------- 5 files changed, 226 insertions(+), 281 deletions(-) diff --git a/plugins/autoclean.c b/plugins/autoclean.c index 0a605e8f2..fff1b41e8 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -23,16 +23,13 @@ static struct command_result *ignore(struct command *timer, static struct command_result *do_clean(struct plugin *p) { - struct json_out *params = json_out_new(NULL); - json_out_start(params, NULL, '{'); - json_out_add(params, "maxexpirytime", false, "%"PRIu64, - time_now().ts.tv_sec - expired_by); - json_out_end(params, '}'); - json_out_finished(params); - /* FIXME: delexpiredinvoice should be in our plugin too! */ - return send_outreq(p, NULL, "delexpiredinvoice", ignore, ignore, p, - take(params)); + struct out_req *req = jsonrpc_request_start(p, NULL, "delexpiredinvoice", + ignore, ignore, p); + json_add_u64(req->js, "maxexpirytime", + time_now().ts.tv_sec - expired_by); + + return send_outreq(p, req); } static struct command_result *json_autocleaninvoice(struct command *cmd, diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 68700ee5a..f16be1c11 100644 --- a/plugins/fundchannel.c +++ b/plugins/fundchannel.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -50,32 +51,6 @@ static void json_out_add_raw_len(struct json_out *jout, memcpy(p, jsonstr, len); } -/* Helper to add a boolean to a json_out */ -static void json_out_addbool(struct json_out *jout, - const char *fieldname, - const bool val) -{ - if (val) - json_out_add(jout, fieldname, false, "true"); - else - json_out_add(jout, fieldname, false, "false"); -} - -/* Copy field and member to output, if it exists: return member */ -static const jsmntok_t *copy_member(struct json_out *ret, - const char *buf, const jsmntok_t *obj, - const char *membername) -{ - const jsmntok_t *m = json_get_member(buf, obj, membername); - if (!m) - return NULL; - - /* Literal copy: it's already JSON escaped, and may be a string. */ - json_out_add_raw_len(ret, membername, - json_tok_full(buf, m), json_tok_full_len(m)); - return m; -} - static struct command_result *send_prior(struct command *cmd, const char *buf, const jsmntok_t *error, @@ -89,23 +64,20 @@ static struct command_result *tx_abort(struct command *cmd, const jsmntok_t *error, struct funding_req *fr) { - struct json_out *ret; + struct out_req *req; /* We stash the error so we can return it after we've cleaned up */ fr->error = json_strdup(fr, buf, error); - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "txid", + req = jsonrpc_request_start(cmd->plugin, cmd, "txdiscard", + send_prior, send_prior, fr); + json_add_string(req->js, "txid", type_to_string(tmpctx, struct bitcoin_txid, &fr->tx_id)); - json_out_end(ret, '}'); /* We need to call txdiscard, and forward the actual cause for the * error after we've cleaned up. We swallow any errors returned by * this call, as we don't really care if it succeeds or not */ - return send_outreq(cmd->plugin, cmd, "txdiscard", - send_prior, send_prior, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } /* We're basically done, we just need to format the output to match @@ -135,7 +107,7 @@ static struct command_result *send_tx(struct command *cmd, struct funding_req *fr) { - struct json_out *ret; + struct out_req *req; const jsmntok_t *tok; bool commitments_secured; @@ -149,15 +121,12 @@ static struct command_result *send_tx(struct command *cmd, tok = json_get_member(buf, result, "channel_id"); fr->chanstr = json_strdup(fr, buf, tok); - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "txid", + req = jsonrpc_request_start(cmd->plugin, cmd, "txsend", + finish, tx_abort, fr); + json_add_string(req->js, "txid", type_to_string(tmpctx, struct bitcoin_txid, &fr->tx_id)); - json_out_end(ret, '}'); - return send_outreq(cmd->plugin, cmd, "txsend", - finish, tx_abort, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *tx_prepare_done(struct command *cmd, @@ -167,7 +136,7 @@ static struct command_result *tx_prepare_done(struct command *cmd, { const jsmntok_t *txid_tok; const jsmntok_t *tx_tok; - struct json_out *ret; + struct out_req *req; const struct bitcoin_tx *tx; const char *hex; u32 outnum; @@ -206,17 +175,14 @@ static struct command_result *tx_prepare_done(struct command *cmd, if (!bitcoin_txid_from_hex(hex, strlen(hex), &fr->tx_id)) plugin_err(cmd->plugin, "Unable to parse txid %s", hex); - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "id", node_id_to_hexstr(tmpctx, fr->id)); + req = jsonrpc_request_start(cmd->plugin, cmd, "fundchannel_complete", + send_tx, tx_abort, fr); + json_add_string(req->js, "id", node_id_to_hexstr(tmpctx, fr->id)); /* Note that hex is reused from above */ - json_out_addstr(ret, "txid", hex); - json_out_add(ret, "txout", false, "%u", outnum); - json_out_end(ret, '}'); + json_add_string(req->js, "txid", hex); + json_add_u32(req->js, "txout", outnum); - return send_outreq(cmd->plugin, cmd, "fundchannel_complete", - send_tx, tx_abort, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *cancel_start(struct command *cmd, @@ -224,59 +190,51 @@ static struct command_result *cancel_start(struct command *cmd, const jsmntok_t *error, struct funding_req *fr) { - struct json_out *ret; + struct out_req *req; /* We stash the error so we can return it after we've cleaned up */ fr->error = json_strdup(fr, buf, error); - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "id", node_id_to_hexstr(tmpctx, fr->id)); - json_out_end(ret, '}'); + req = jsonrpc_request_start(cmd->plugin, cmd, "fundchannel_cancel", + send_prior, send_prior, fr); + json_add_string(req->js, "id", node_id_to_hexstr(tmpctx, fr->id)); - return send_outreq(cmd->plugin, cmd, "fundchannel_cancel", - send_prior, send_prior, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } -static struct json_out *txprepare(struct command *cmd, - struct funding_req *fr, - const char *destination) +static void txprepare(struct json_stream *js, + struct funding_req *fr, + const char *destination) { - struct json_out *ret; - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - /* Add the 'outputs' */ - json_out_start(ret, "outputs", '['); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, destination, fr->funding_str); - json_out_end(ret, '}'); - json_out_end(ret, ']'); + json_array_start(js, "outputs"); + json_object_start(js, NULL); + json_add_string(js, destination, fr->funding_str); + json_object_end(js); + json_array_end(js); if (fr->feerate_str) - json_out_addstr(ret, "feerate", fr->feerate_str); + json_add_string(js, "feerate", fr->feerate_str); if (fr->minconf) - json_out_add(ret, "minconf", false, "%u", *fr->minconf); + json_add_u32(js, "minconf", *fr->minconf); if (fr->utxo_str) - json_out_add_raw_len(ret, "utxos", fr->utxo_str, strlen(fr->utxo_str)); - json_out_end(ret, '}'); - - return ret; + json_out_add_raw_len(js->jout, "utxos", fr->utxo_str, + strlen(fr->utxo_str)); } static struct command_result *prepare_actual(struct command *cmd, - const char *buf, - const jsmntok_t *result, - struct funding_req *fr) + const char *buf, + const jsmntok_t *result, + struct funding_req *fr) { - struct json_out *ret; + struct out_req *req; - ret = txprepare(cmd, fr, fr->funding_addr); + req = jsonrpc_request_start(cmd->plugin, cmd, "txprepare", + tx_prepare_done, cancel_start, + fr); + txprepare(req->js, fr, fr->funding_addr); - return send_outreq(cmd->plugin, cmd, "txprepare", - tx_prepare_done, cancel_start, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *fundchannel_start_done(struct command *cmd, @@ -284,7 +242,7 @@ static struct command_result *fundchannel_start_done(struct command *cmd, const jsmntok_t *result, struct funding_req *fr) { - struct json_out *ret; + struct out_req *req; /* Save the outscript so we can fund the outnum later */ fr->out_script = json_tok_bin_from_hex(fr, buf, @@ -295,44 +253,39 @@ static struct command_result *fundchannel_start_done(struct command *cmd, json_get_member(buf, result, "funding_address")); /* Now that we're ready to go, cancel the reserved tx */ - ret = json_out_new(NULL); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "txid", + req = jsonrpc_request_start(cmd->plugin, cmd, "txdiscard", + prepare_actual, cancel_start, + fr); + json_add_string(req->js, "txid", type_to_string(tmpctx, struct bitcoin_txid, &fr->tx_id)); - json_out_end(ret, '}'); - return send_outreq(cmd->plugin, cmd, "txdiscard", - prepare_actual, cancel_start, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *fundchannel_start(struct command *cmd, struct funding_req *fr) { - struct json_out *ret = json_out_new(NULL); + struct out_req *req = jsonrpc_request_start(cmd->plugin, cmd, + "fundchannel_start", + fundchannel_start_done, + tx_abort, fr); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "id", node_id_to_hexstr(tmpctx, fr->id)); + json_add_string(req->js, "id", node_id_to_hexstr(tmpctx, fr->id)); if (deprecated_apis) - json_out_addstr(ret, "satoshi", fr->funding_str); + json_add_string(req->js, "satoshi", fr->funding_str); else - json_out_addstr(ret, "amount", fr->funding_str); + json_add_string(req->js, "amount", fr->funding_str); if (fr->feerate_str) - json_out_addstr(ret, "feerate", fr->feerate_str); + json_add_string(req->js, "feerate", fr->feerate_str); if (fr->announce_channel) - json_out_addbool(ret, "announce", *fr->announce_channel); + json_add_bool(req->js, "announce", *fr->announce_channel); if (fr->push_msat) - json_out_addstr(ret, "push_msat", + json_add_string(req->js, "push_msat", type_to_string(tmpctx, struct amount_msat, fr->push_msat)); - json_out_end(ret, '}'); - json_out_finished(ret); - - return send_outreq(cmd->plugin, cmd, "fundchannel_start", - fundchannel_start_done, tx_abort, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *post_dryrun(struct command *cmd, @@ -391,31 +344,28 @@ static struct command_result *exec_dryrun(struct command *cmd, const jsmntok_t *result, struct funding_req *fr) { - struct json_out *ret; + struct out_req *req = jsonrpc_request_start(cmd->plugin, cmd, "txprepare", + post_dryrun, forward_error, + fr); /* Now that we've tried connecting, we do a 'dry-run' of txprepare, * so we can get an accurate idea of the funding amount */ - ret = txprepare(cmd, fr, placeholder_funding_addr); + txprepare(req->js, fr, placeholder_funding_addr); - return send_outreq(cmd->plugin, cmd, "txprepare", - post_dryrun, forward_error, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } static struct command_result *connect_to_peer(struct command *cmd, struct funding_req *fr) { - struct json_out *ret = json_out_new(NULL); + struct out_req *req = jsonrpc_request_start(cmd->plugin, cmd, "connect", + exec_dryrun, forward_error, + fr); - json_out_start(ret, NULL, '{'); - json_out_addstr(ret, "id", node_id_to_hexstr(tmpctx, fr->id)); - json_out_end(ret, '}'); - json_out_finished(ret); + json_add_string(req->js, "id", node_id_to_hexstr(tmpctx, fr->id)); - return send_outreq(cmd->plugin, cmd, "connect", - exec_dryrun, forward_error, - fr, take(ret)); + return send_outreq(cmd->plugin, req); } /* We will use 'id' and 'amount' to build a output: {id: amount}. diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 7354b31f1..bdb878171 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -28,24 +28,6 @@ struct plugin_timer { struct command_result *(*cb)(struct plugin *p); }; -struct out_req { - /* The unique id of this request. */ - u64 id; - /* The command which is why we're calling this rpc. */ - struct command *cmd; - /* The callback when we get a response. */ - struct command_result *(*cb)(struct command *command, - const char *buf, - const jsmntok_t *result, - void *arg); - /* The callback when we get an error. */ - struct command_result *(*errcb)(struct command *command, - const char *buf, - const jsmntok_t *error, - void *arg); - void *arg; -}; - struct rpc_conn { int fd; MEMBUF(char) mb; @@ -132,6 +114,39 @@ static void ld_rpc_send(struct plugin *plugin, struct json_stream *stream) /* FIXME: Move lightningd/jsonrpc to common/ ? */ +struct out_req * +jsonrpc_request_start_(struct plugin *plugin, struct command *cmd, + const char *method, + struct command_result *(*cb)(struct command *command, + const char *buf, + const jsmntok_t *result, + void *arg), + struct command_result *(*errcb)(struct command *command, + const char *buf, + const jsmntok_t *result, + void *arg), + void *arg) +{ + struct out_req *out; + + out = tal(plugin, struct out_req); + out->id = plugin->next_outreq_id++; + out->cmd = cmd; + out->cb = cb; + out->errcb = errcb; + out->arg = arg; + uintmap_add(&plugin->out_reqs, out->id, out); + + out->js = new_json_stream(NULL, cmd, NULL); + json_object_start(out->js, NULL); + json_add_string(out->js, "jsonrpc", "2.0"); + json_add_u64(out->js, "id", out->id); + json_add_string(out->js, "method", method); + json_object_start(out->js, "params"); + + return out; +} + static void jsonrpc_finish_and_send(struct plugin *p, struct json_stream *js) { json_object_compat_end(js); @@ -524,43 +539,14 @@ static void handle_rpc_reply(struct plugin *plugin, const jsmntok_t *toks) } struct command_result * -send_outreq_(struct plugin *plugin, - struct command *cmd, - const char *method, - struct command_result *(*cb)(struct command *command, - const char *buf, - const jsmntok_t *result, - void *arg), - struct command_result *(*errcb)(struct command *command, - const char *buf, - const jsmntok_t *result, - void *arg), - void *arg, - const struct json_out *params TAKES) +send_outreq(struct plugin *plugin, const struct out_req *req) { - struct json_stream *js; - struct out_req *out; + /* The "param" object. */ + json_object_end(req->js); + json_object_compat_end(req->js); + json_stream_close(req->js, req->cmd); - out = tal(plugin, struct out_req); - out->id = plugin->next_outreq_id++; - out->cmd = cmd; - out->cb = cb; - out->errcb = errcb; - out->arg = arg; - uintmap_add(&plugin->out_reqs, out->id, out); - - js = new_json_stream(NULL, NULL, NULL); - json_object_start(js, NULL); - json_add_string(js, "jsonrpc", "2.0"); - json_add_u64(js, "id", out->id); - json_add_string(js, "method", method); - json_out_add_splice(js->jout, "params", params); - json_object_compat_end(js); - json_stream_close(js, NULL); - ld_rpc_send(plugin, js); - - if (taken(params)) - tal_free(params); + ld_rpc_send(plugin, req->js); return &pending; } @@ -581,7 +567,7 @@ handle_getmanifest(struct command *getmanifest_cmd) } json_array_end(params); - json_object_start(params, "rpcmethods"); + json_array_start(params, "rpcmethods"); for (size_t i = 0; i < p->num_commands; i++) { json_object_start(params, NULL); json_add_string(params, "name", p->commands[i].name); diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 4bc5f682a..829a6ab8e 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -27,6 +27,26 @@ enum plugin_restartability { PLUGIN_RESTARTABLE }; +struct out_req { + /* The unique id of this request. */ + u64 id; + /* The command which is why we're calling this rpc. */ + struct command *cmd; + /* The request stream. */ + struct json_stream *js; + /* The callback when we get a response. */ + struct command_result *(*cb)(struct command *command, + const char *buf, + const jsmntok_t *result, + void *arg); + /* The callback when we get an error. */ + struct command_result *(*errcb)(struct command *command, + const char *buf, + const jsmntok_t *error, + void *arg); + void *arg; +}; + struct command { u64 *id; const char *methodname; @@ -70,6 +90,35 @@ struct plugin_hook { const jsmntok_t *params); }; +/* Helper to create a JSONRPC2 request stream. Send it with `send_outreq`. */ +struct out_req * +jsonrpc_request_start_(struct plugin *plugin, struct command *cmd, + const char *method, + struct command_result *(*cb)(struct command *command, + const char *buf, + const jsmntok_t *result, + void *arg), + struct command_result *(*errcb)(struct command *command, + const char *buf, + const jsmntok_t *result, + void *arg), + void *arg); + +#define jsonrpc_request_start(plugin, cmd, method, cb, errcb, arg) \ + jsonrpc_request_start_((plugin), (cmd), (method), \ + typesafe_cb_preargs(struct command_result *, void *, \ + (cb), (arg), \ + struct command *command, \ + const char *buf, \ + const jsmntok_t *result), \ + typesafe_cb_preargs(struct command_result *, void *, \ + (errcb), (arg), \ + struct command *command, \ + const char *buf, \ + const jsmntok_t *result), \ + (arg)) + + /* Helper to create a JSONRPC2 response stream with a "result" object. */ struct json_stream *jsonrpc_stream_success(struct command *cmd); @@ -131,38 +180,9 @@ const char *rpc_delve(const tal_t *ctx, const struct json_out *params TAKES, const char *guide); -/* Async rpc request. - * @cmd can be NULL if we're coming from a timer callback. - * @params can be NULL, otherwise it's an array or object. - */ +/* Send an async rpc request to lightningd. */ struct command_result * -send_outreq_(struct plugin *plugin, - struct command *cmd, - const char *method, - struct command_result *(*cb)(struct command *command, - const char *buf, - const jsmntok_t *result, - void *arg), - struct command_result *(*errcb)(struct command *command, - const char *buf, - const jsmntok_t *result, - void *arg), - void *arg, - const struct json_out *params TAKES); - -#define send_outreq(plugin, cmd, method, cb, errcb, arg, params) \ - send_outreq_((plugin), (cmd), (method), \ - typesafe_cb_preargs(struct command_result *, void *, \ - (cb), (arg), \ - struct command *command, \ - const char *buf, \ - const jsmntok_t *result), \ - typesafe_cb_preargs(struct command_result *, void *, \ - (errcb), (arg), \ - struct command *command, \ - const char *buf, \ - const jsmntok_t *result), \ - (arg), (params)) +send_outreq(struct plugin *plugin, const struct out_req *req); /* Callback to just forward error and close request; @cmd cannot be NULL */ struct command_result *forward_error(struct command *cmd, diff --git a/plugins/pay.c b/plugins/pay.c index 48632d4c9..1ec8790a3 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -197,14 +198,6 @@ static void attempt_failed_tok(struct pay_command *pc, const char *method, failed_end(failed); } -/* Helper to add a u32. */ -static void json_out_add_u32(struct json_out *jout, - const char *fieldname, - u32 val) -{ - json_out_add(jout, fieldname, false, "%"PRIu32, val); -} - /* Helper to add a u64. */ static void json_out_add_u64(struct json_out *jout, const char *fieldname, @@ -360,7 +353,7 @@ execute_waitblockheight(struct command *cmd, u32 blockheight, struct pay_command *pc) { - struct json_out *params; + struct out_req *req; struct timeabs now = time_now(); struct timerel remaining; @@ -369,18 +362,14 @@ execute_waitblockheight(struct command *cmd, remaining = time_between(pc->stoptime, now); - params = json_out_new(tmpctx); - json_out_start(params, NULL, '{'); - json_out_add_u32(params, "blockheight", blockheight); - json_out_add_u64(params, "timeout", time_to_sec(remaining)); - json_out_end(params, '}'); - json_out_finished(params); + req = jsonrpc_request_start(cmd->plugin, cmd, "waitblockheight", + &waitblockheight_done, + &waitblockheight_error, + pc); + json_add_u32(req->js, "blockheight", blockheight); + json_add_u32(req->js, "timeout", time_to_sec(remaining)); - return send_outreq(cmd->plugin, cmd, "waitblockheight", - &waitblockheight_done, - &waitblockheight_error, - pc, - params); + return send_outreq(cmd->plugin, req); } /* Gets the remote height from a @@ -581,10 +570,13 @@ static struct command_result *sendpay_done(struct command *cmd, const jsmntok_t *result, struct pay_command *pc) { - return send_outreq(cmd->plugin, cmd, "waitsendpay", - waitsendpay_done, waitsendpay_error, pc, - take(json_out_obj(NULL, "payment_hash", - pc->payment_hash))); + struct out_req *req = jsonrpc_request_start(cmd->plugin, cmd, + "waitsendpay", + waitsendpay_done, + waitsendpay_error, pc); + json_add_string(req->js, "payment_hash", pc->payment_hash); + + return send_outreq(cmd->plugin, req); } /* Calculate how many millisatoshi we need at the start of this route @@ -737,7 +729,7 @@ static struct command_result *getroute_done(struct command *cmd, struct amount_msat fee; u32 delay; double feepercent; - struct json_out *params; + struct out_req *req; if (!t) plugin_err(cmd->plugin, "getroute gave no 'route'? '%.*s'", @@ -837,21 +829,17 @@ static struct command_result *getroute_done(struct command *cmd, } attempt->sendpay = true; - params = json_out_new(NULL); - json_out_start(params, NULL, '{'); - json_out_add_raw(params, "route", attempt->route); - json_out_add(params, "payment_hash", true, "%s", pc->payment_hash); - json_out_add(params, "bolt11", true, "%s", pc->ps->bolt11); + req = jsonrpc_request_start(cmd->plugin, cmd, "sendpay", + sendpay_done, sendpay_error, pc); + json_out_add_raw(req->js->jout, "route", attempt->route); + json_add_string(req->js, "payment_hash", pc->payment_hash); + json_add_string(req->js, "bolt11", pc->ps->bolt11); if (pc->label) - json_out_add(params, "label", true, "%s", pc->label); + json_add_string(req->js, "label", pc->label); if (pc->payment_secret) - json_out_add(params, "payment_secret", true, "%s", - pc->payment_secret); - json_out_end(params, '}'); - - return send_outreq(cmd->plugin, cmd, "sendpay", sendpay_done, sendpay_error, pc, - take(params)); + json_add_string(req->js, "payment_secret", pc->payment_secret); + return send_outreq(cmd->plugin, req); } static struct command_result *getroute_error(struct command *cmd, @@ -896,7 +884,7 @@ static struct command_result *execute_getroute(struct command *cmd, struct amount_msat msat; const char *dest; u32 cltv; - struct json_out *params; + struct out_req *req; /* routehint set below. */ @@ -929,24 +917,22 @@ static struct command_result *execute_getroute(struct command *cmd, } /* OK, ask for route to destination */ - params = json_out_new(NULL); - json_out_start(params, NULL, '{'); - json_out_addstr(params, "id", dest); - json_out_addstr(params, "msatoshi", + req = jsonrpc_request_start(cmd->plugin, cmd, "getroute", + getroute_done, getroute_error, pc); + json_add_string(req->js, "id", dest); + json_add_string(req->js, "msatoshi", type_to_string(tmpctx, struct amount_msat, &msat)); - json_out_add_u32(params, "cltv", cltv); - json_out_add_u32(params, "maxhops", max_hops); - json_out_add(params, "riskfactor", false, "%f", pc->riskfactor); + json_add_u32(req->js, "cltv", cltv); + json_add_u32(req->js, "maxhops", max_hops); + json_add_member(req->js, "riskfactor", false, "%f", pc->riskfactor); if (tal_count(pc->excludes) != 0) { - json_out_start(params, "exclude", '['); + json_array_start(req->js, "exclude"); for (size_t i = 0; i < tal_count(pc->excludes); i++) - json_out_addstr(params, NULL, pc->excludes[i]); - json_out_end(params, ']'); + json_add_string(req->js, NULL, pc->excludes[i]); + json_array_end(req->js); } - json_out_end(params, '}'); - return send_outreq(cmd->plugin, cmd, "getroute", getroute_done, getroute_error, pc, - take(params)); + return send_outreq(cmd->plugin, req); } static struct command_result * @@ -989,11 +975,11 @@ static struct command_result * execute_getstartblockheight(struct command *cmd, struct pay_command *pc) { - return send_outreq(cmd->plugin, cmd, "getinfo", - &getstartblockheight_done, - &getstartblockheight_error, - pc, - take(json_out_obj(NULL, NULL, NULL))); + struct out_req *req = jsonrpc_request_start(cmd->plugin, cmd, "getinfo", + &getstartblockheight_done, + &getstartblockheight_error, + pc); + return send_outreq(cmd->plugin, req); } static struct command_result *start_pay_attempt(struct command *cmd, @@ -1106,6 +1092,8 @@ static struct command_result *add_shadow_route(struct command *cmd, static struct command_result *shadow_route(struct command *cmd, struct pay_command *pc) { + struct out_req *req; + #if DEVELOPER if (!pc->use_shadow) return start_pay_attempt(cmd, pc, "Initial attempt"); @@ -1113,9 +1101,9 @@ static struct command_result *shadow_route(struct command *cmd, if (pseudorand(2) == 0) return start_pay_attempt(cmd, pc, "Initial attempt"); - return send_outreq(cmd->plugin, cmd, "listchannels", - add_shadow_route, forward_error, pc, - take(json_out_obj(NULL, "source", pc->shadow_dest))); + req = jsonrpc_request_start(cmd->plugin, cmd, "listchannels", + add_shadow_route, forward_error, pc); + return send_outreq(cmd->plugin, req); } /* gossipd doesn't know much about the current state of channels; here we @@ -1271,6 +1259,7 @@ static struct command_result *json_pay(struct command *cmd, double *maxfeepercent; unsigned int *maxdelay; struct amount_msat *exemptfee; + struct out_req *req; #if DEVELOPER bool *use_shadow; #endif @@ -1357,8 +1346,9 @@ static struct command_result *json_pay(struct command *cmd, #endif /* Get capacities of local channels (no parameters) */ - return send_outreq(cmd->plugin, cmd, "listpeers", listpeers_done, forward_error, pc, - take(json_out_obj(NULL, NULL, NULL))); + req = jsonrpc_request_start(cmd->plugin, cmd, "listpeers", + listpeers_done, forward_error, pc); + return send_outreq(cmd->plugin, req); } /* FIXME: Add this to ccan/time? */ @@ -1663,6 +1653,7 @@ static struct command_result *json_listpays(struct command *cmd, const jsmntok_t *params) { const char *b11str; + struct out_req *req; /* FIXME: would be nice to parse as a bolt11 so check worked in future */ if (!param(cmd, buf, params, @@ -1670,11 +1661,12 @@ static struct command_result *json_listpays(struct command *cmd, NULL)) return command_param_failed(); - return send_outreq(cmd->plugin, cmd, "listsendpays", - listsendpays_done, forward_error, - cast_const(char *, b11str), - /* Neatly returns empty object if b11str is NULL */ - take(json_out_obj(NULL, "bolt11", b11str))); + req = jsonrpc_request_start(cmd->plugin, cmd, "listsendpays", + listsendpays_done, forward_error, + cast_const(char *, b11str)); + if (b11str) + json_add_string(req->js, "bolt11", b11str); + return send_outreq(cmd->plugin, req); } static void init(struct plugin *p,