mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-23 00:54:20 +01:00
Move json and param core functionality into common, for plugins.
json_escaped.[ch], param.[ch] and jsonrpc_errors.h move from lightningd/ to common/. Tests moved too. We add a new 'common/json_tok.[ch]' for the common parameter parsing routines which a plugin might want, taking them out of lightningd/json.c (which now only contains the lightningd-specific ones). The rest is mainly fixing up includes. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -34,8 +34,11 @@ LIGHTNINGD_COMMON_OBJS := \
|
||||
common/key_derive.o \
|
||||
common/io_lock.o \
|
||||
common/json.o \
|
||||
common/json_escaped.o \
|
||||
common/json_tok.o \
|
||||
common/memleak.o \
|
||||
common/msg_queue.o \
|
||||
common/param.o \
|
||||
common/permute_tx.o \
|
||||
common/pseudorand.o \
|
||||
common/sphinx.o \
|
||||
@@ -64,7 +67,6 @@ LIGHTNINGD_SRC := \
|
||||
lightningd/htlc_end.c \
|
||||
lightningd/invoice.c \
|
||||
lightningd/json.c \
|
||||
lightningd/json_escaped.c \
|
||||
lightningd/json_stream.c \
|
||||
lightningd/jsonrpc.c \
|
||||
lightningd/lightningd.c \
|
||||
@@ -74,7 +76,6 @@ LIGHTNINGD_SRC := \
|
||||
lightningd/onchain_control.c \
|
||||
lightningd/opening_control.c \
|
||||
lightningd/options.c \
|
||||
lightningd/param.c \
|
||||
lightningd/pay.c \
|
||||
lightningd/payalgo.c \
|
||||
lightningd/peer_control.c \
|
||||
@@ -92,8 +93,7 @@ ALL_OBJS += $(LIGHTNINGD_OBJS)
|
||||
# We accumulate all lightningd/ headers in these three:
|
||||
LIGHTNINGD_HEADERS_NOGEN = \
|
||||
$(LIGHTNINGD_SRC:.c=.h) \
|
||||
lightningd/channel_state.h \
|
||||
lightningd/jsonrpc_errors.h
|
||||
lightningd/channel_state.h
|
||||
|
||||
# Generated headers
|
||||
LIGHTNINGD_HEADERS_GEN = \
|
||||
|
||||
@@ -13,14 +13,15 @@
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/utils.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/channel_control.h>
|
||||
#include <lightningd/gossip_control.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/param.h>
|
||||
|
||||
/* Mutual recursion via timer. */
|
||||
static void try_extend_tip(struct chain_topology *topo);
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
#include <ccan/list/list.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/features.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/wireaddr.h>
|
||||
@@ -18,11 +21,9 @@
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_stream.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/opening_control.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
#include <ccan/take/take.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/features.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <errno.h>
|
||||
@@ -22,12 +26,9 @@
|
||||
#include <lightningd/gossip_msg.h>
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/ping.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "invoice.h"
|
||||
#include "json.h"
|
||||
#include "jsonrpc.h"
|
||||
#include "jsonrpc_errors.h"
|
||||
#include "lightningd.h"
|
||||
#include <bitcoin/address.h>
|
||||
#include <bitcoin/base58.h>
|
||||
@@ -10,6 +9,10 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/bech32.h>
|
||||
#include <common/bolt11.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/utils.h>
|
||||
#include <errno.h>
|
||||
@@ -18,11 +21,8 @@
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/channel.h>
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/json.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/wireaddr.h>
|
||||
#include <gossipd/routing.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/json_stream.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <sys/socket.h>
|
||||
#include <wallet/wallet.h>
|
||||
@@ -95,175 +97,6 @@ void json_add_txid(struct json_stream *result, const char *fieldname,
|
||||
json_add_string(result, fieldname, hex);
|
||||
}
|
||||
|
||||
bool json_tok_array(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
const jsmntok_t **arr)
|
||||
{
|
||||
if (tok->type == JSMN_ARRAY)
|
||||
return (*arr = tok);
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be an array, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_bool(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
bool **b)
|
||||
{
|
||||
*b = tal(cmd, bool);
|
||||
if (tok->type == JSMN_PRIMITIVE) {
|
||||
if (memeqstr(buffer + tok->start, tok->end - tok->start, "true")) {
|
||||
**b = true;
|
||||
return true;
|
||||
}
|
||||
if (memeqstr(buffer + tok->start, tok->end - tok->start, "false")) {
|
||||
**b = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be 'true' or 'false', not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_double(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
double **num)
|
||||
{
|
||||
*num = tal(cmd, double);
|
||||
if (json_to_double(buffer, tok, *num))
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a double, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_escaped_string(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
const char **str)
|
||||
{
|
||||
struct json_escaped *esc = json_to_escaped_string(cmd, buffer, tok);
|
||||
if (esc) {
|
||||
*str = json_escaped_unescape(cmd, esc);
|
||||
if (*str)
|
||||
return true;
|
||||
}
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a string, not '%.*s'"
|
||||
" (note, we don't allow \\u)",
|
||||
name,
|
||||
tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_string(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
const char **str)
|
||||
{
|
||||
*str = tal_strndup(cmd, buffer + tok->start,
|
||||
tok->end - tok->start);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool json_tok_label(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
struct json_escaped **label)
|
||||
{
|
||||
/* We accept both strings and number literals here. */
|
||||
*label = json_escaped_string_(cmd, buffer + tok->start, tok->end - tok->start);
|
||||
if (*label && (tok->type == JSMN_STRING || json_tok_is_num(buffer, tok)))
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a string or number, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_number(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
unsigned int **num)
|
||||
{
|
||||
*num = tal(cmd, unsigned int);
|
||||
if (json_to_number(buffer, tok, *num))
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be an integer, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_sha256(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct sha256 **hash)
|
||||
{
|
||||
*hash = tal(cmd, struct sha256);
|
||||
if (hex_decode(buffer + tok->start,
|
||||
tok->end - tok->start,
|
||||
*hash, sizeof(**hash)))
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a 32 byte hex value, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_msat(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t * tok,
|
||||
u64 **msatoshi_val)
|
||||
{
|
||||
if (json_tok_streq(buffer, tok, "any")) {
|
||||
*msatoshi_val = NULL;
|
||||
return true;
|
||||
}
|
||||
*msatoshi_val = tal(cmd, u64);
|
||||
|
||||
if (json_to_u64(buffer, tok, *msatoshi_val) && *msatoshi_val != 0)
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a positive number or 'any', not '%.*s'",
|
||||
name,
|
||||
tok->end - tok->start,
|
||||
buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_percent(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
double **num)
|
||||
{
|
||||
*num = tal(cmd, double);
|
||||
if (json_to_double(buffer, tok, *num) && **num >= 0.0)
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a positive double, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_tok_u64(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
uint64_t **num)
|
||||
{
|
||||
*num = tal(cmd, uint64_t);
|
||||
if (json_to_u64(buffer, tok, *num))
|
||||
return true;
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be an unsigned 64 bit integer, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_to_pubkey(const char *buffer, const jsmntok_t *tok,
|
||||
struct pubkey *pubkey)
|
||||
{
|
||||
@@ -470,13 +303,6 @@ void json_add_address_internal(struct json_stream *response,
|
||||
abort();
|
||||
}
|
||||
|
||||
bool json_tok_tok(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t * tok,
|
||||
const jsmntok_t **out)
|
||||
{
|
||||
return (*out = tok);
|
||||
}
|
||||
|
||||
void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value)
|
||||
{
|
||||
json_add_member(result, fieldname, "%u", value);
|
||||
|
||||
@@ -47,56 +47,6 @@ void json_add_pubkey(struct json_stream *response,
|
||||
void json_add_txid(struct json_stream *result, const char *fieldname,
|
||||
const struct bitcoin_txid *txid);
|
||||
|
||||
/* Extract json array token */
|
||||
bool json_tok_array(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
const jsmntok_t **arr);
|
||||
|
||||
/* Extract boolean this (must be a true or false) */
|
||||
bool json_tok_bool(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
bool **b);
|
||||
|
||||
/* Extract double from this (must be a number literal) */
|
||||
bool json_tok_double(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
double **num);
|
||||
|
||||
/* Extract an escaped string (and unescape it) */
|
||||
bool json_tok_escaped_string(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
const char **str);
|
||||
|
||||
/* Extract a string */
|
||||
bool json_tok_string(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
const char **str);
|
||||
|
||||
/* Extract a label. It is either an escaped string or a number. */
|
||||
bool json_tok_label(struct command *cmd, const char *name,
|
||||
const char * buffer, const jsmntok_t *tok,
|
||||
struct json_escaped **label);
|
||||
|
||||
/* Extract number from this (may be a string, or a number literal) */
|
||||
bool json_tok_number(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
unsigned int **num);
|
||||
|
||||
/* Extract sha256 hash */
|
||||
bool json_tok_sha256(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct sha256 **hash);
|
||||
|
||||
/* Extract positive integer, or NULL if tok is 'any'. */
|
||||
bool json_tok_msat(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t * tok,
|
||||
u64 **msatoshi_val);
|
||||
|
||||
/* Extract double in range [0.0, 100.0] */
|
||||
bool json_tok_percent(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
double **num);
|
||||
|
||||
/* Extract a pubkey from this */
|
||||
bool json_to_pubkey(const char *buffer, const jsmntok_t *tok,
|
||||
struct pubkey *pubkey);
|
||||
@@ -113,11 +63,6 @@ bool json_tok_short_channel_id(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct short_channel_id **scid);
|
||||
|
||||
/* Extract number from this (may be a string, or a number literal) */
|
||||
bool json_tok_u64(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
uint64_t **num);
|
||||
|
||||
enum feerate_style {
|
||||
FEERATE_PER_KSIPA,
|
||||
FEERATE_PER_KBYTE
|
||||
@@ -152,14 +97,6 @@ void json_add_address_internal(struct json_stream *response,
|
||||
const char *fieldname,
|
||||
const struct wireaddr_internal *addr);
|
||||
|
||||
/*
|
||||
* Set the address of @out to @tok. Used as a callback by handlers that
|
||||
* want to unmarshal @tok themselves.
|
||||
*/
|
||||
bool json_tok_tok(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t * tok,
|
||||
const jsmntok_t **out);
|
||||
|
||||
|
||||
/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. Turns
|
||||
* any non-printable chars into JSON escapes, but leaves existing escapes alone.
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct json_escaped *json_escaped_string_(const tal_t *ctx,
|
||||
const void *bytes, size_t len)
|
||||
{
|
||||
struct json_escaped *esc;
|
||||
|
||||
esc = (void *)tal_arr_label(ctx, char, len + 1,
|
||||
TAL_LABEL(struct json_escaped, ""));
|
||||
memcpy(esc->s, bytes, len);
|
||||
esc->s[len] = '\0';
|
||||
return esc;
|
||||
}
|
||||
|
||||
struct json_escaped *json_to_escaped_string(const tal_t *ctx,
|
||||
const char *buffer,
|
||||
const jsmntok_t *tok)
|
||||
{
|
||||
if (tok->type != JSMN_STRING)
|
||||
return NULL;
|
||||
/* jsmn always gives us ~ well-formed strings. */
|
||||
return json_escaped_string_(ctx, buffer + tok->start,
|
||||
tok->end - tok->start);
|
||||
}
|
||||
|
||||
bool json_escaped_eq(const struct json_escaped *a,
|
||||
const struct json_escaped *b)
|
||||
{
|
||||
return streq(a->s, b->s);
|
||||
}
|
||||
|
||||
static struct json_escaped *escape(const tal_t *ctx,
|
||||
const char *str TAKES,
|
||||
bool partial)
|
||||
{
|
||||
struct json_escaped *esc;
|
||||
size_t i, n;
|
||||
|
||||
/* Worst case: all \uXXXX */
|
||||
esc = (struct json_escaped *)tal_arr(ctx, char, strlen(str) * 6 + 1);
|
||||
|
||||
for (i = n = 0; str[i]; i++, n++) {
|
||||
char escape = 0;
|
||||
switch (str[i]) {
|
||||
case '\n':
|
||||
escape = 'n';
|
||||
break;
|
||||
case '\b':
|
||||
escape = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
escape = 'f';
|
||||
break;
|
||||
case '\t':
|
||||
escape = 't';
|
||||
break;
|
||||
case '\r':
|
||||
escape = 'r';
|
||||
break;
|
||||
case '\\':
|
||||
if (partial) {
|
||||
/* Don't double-escape standard escapes. */
|
||||
if (str[i+1] == 'n'
|
||||
|| str[i+1] == 'b'
|
||||
|| str[i+1] == 'f'
|
||||
|| str[i+1] == 't'
|
||||
|| str[i+1] == 'r'
|
||||
|| str[i+1] == '/'
|
||||
|| str[i+1] == '\\'
|
||||
|| str[i+1] == '"') {
|
||||
escape = str[i+1];
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (str[i+1] == 'u'
|
||||
&& cisxdigit(str[i+2])
|
||||
&& cisxdigit(str[i+3])
|
||||
&& cisxdigit(str[i+4])
|
||||
&& cisxdigit(str[i+5])) {
|
||||
memcpy(esc->s + n, str + i, 6);
|
||||
n += 5;
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
} /* fall thru */
|
||||
case '"':
|
||||
escape = str[i];
|
||||
break;
|
||||
default:
|
||||
if ((unsigned)str[i] < ' ' || str[i] == 127) {
|
||||
snprintf(esc->s + n, 7, "\\u%04X", str[i]);
|
||||
n += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (escape) {
|
||||
esc->s[n++] = '\\';
|
||||
esc->s[n] = escape;
|
||||
} else
|
||||
esc->s[n] = str[i];
|
||||
}
|
||||
|
||||
esc->s[n] = '\0';
|
||||
if (taken(str))
|
||||
tal_free(str);
|
||||
return esc;
|
||||
}
|
||||
|
||||
struct json_escaped *json_partial_escape(const tal_t *ctx, const char *str TAKES)
|
||||
{
|
||||
return escape(ctx, str, true);
|
||||
}
|
||||
|
||||
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES)
|
||||
{
|
||||
return escape(ctx, str, false);
|
||||
}
|
||||
|
||||
/* By policy, we don't handle \u. Use UTF-8. */
|
||||
const char *json_escaped_unescape(const tal_t *ctx,
|
||||
const struct json_escaped *esc)
|
||||
{
|
||||
char *unesc = tal_arr(ctx, char, strlen(esc->s) + 1);
|
||||
size_t i, n;
|
||||
|
||||
for (i = n = 0; esc->s[i]; i++, n++) {
|
||||
if (esc->s[i] != '\\') {
|
||||
unesc[n] = esc->s[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
switch (esc->s[i]) {
|
||||
case 'n':
|
||||
unesc[n] = '\n';
|
||||
break;
|
||||
case 'b':
|
||||
unesc[n] = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
unesc[n] = '\f';
|
||||
break;
|
||||
case 't':
|
||||
unesc[n] = '\t';
|
||||
break;
|
||||
case 'r':
|
||||
unesc[n] = '\r';
|
||||
break;
|
||||
case '/':
|
||||
case '\\':
|
||||
case '"':
|
||||
unesc[n] = esc->s[i];
|
||||
break;
|
||||
default:
|
||||
return tal_free(unesc);
|
||||
}
|
||||
}
|
||||
|
||||
unesc[n] = '\0';
|
||||
return unesc;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_JSON_ESCAPED_H
|
||||
#define LIGHTNING_LIGHTNINGD_JSON_ESCAPED_H
|
||||
#include "config.h"
|
||||
#include <common/json.h>
|
||||
|
||||
/* Type differentiation for a correctly-escaped JSON string */
|
||||
struct json_escaped {
|
||||
/* NUL terminated string. */
|
||||
char s[1];
|
||||
};
|
||||
|
||||
/* @str be a valid UTF-8 string */
|
||||
struct json_escaped *json_escape(const tal_t *ctx, const char *str TAKES);
|
||||
|
||||
/* @str is a valid UTF-8 string which may already contain escapes. */
|
||||
struct json_escaped *json_partial_escape(const tal_t *ctx,
|
||||
const char *str TAKES);
|
||||
|
||||
/* Extract a JSON-escaped string. */
|
||||
struct json_escaped *json_to_escaped_string(const tal_t *ctx,
|
||||
const char *buffer,
|
||||
const jsmntok_t *tok);
|
||||
|
||||
/* Are two escaped json strings identical? */
|
||||
bool json_escaped_eq(const struct json_escaped *a,
|
||||
const struct json_escaped *b);
|
||||
|
||||
/* Internal routine for creating json_escaped from bytes. */
|
||||
struct json_escaped *json_escaped_string_(const tal_t *ctx,
|
||||
const void *bytes, size_t len);
|
||||
|
||||
/* Be very careful here! Can fail! Doesn't handle \u: use UTF-8 please. */
|
||||
const char *json_escaped_unescape(const tal_t *ctx,
|
||||
const struct json_escaped *esc);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_JSON_ESCAPED_H */
|
||||
@@ -24,7 +24,10 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/bech32.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/version.h>
|
||||
#include <common/wallet_tx.h>
|
||||
@@ -33,12 +36,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -64,7 +64,7 @@ struct json_stream *json_stream_success(struct command *cmd);
|
||||
/**
|
||||
* json_stream_fail - start streaming a failed json result.
|
||||
* @cmd: the command we're running.
|
||||
* @code: the error code from lightningd/jsonrpc_errors.h
|
||||
* @code: the error code from common/jsonrpc_errors.h
|
||||
* @errmsg: the error string.
|
||||
*
|
||||
* The returned value should go to command_failed() when done;
|
||||
@@ -77,7 +77,7 @@ struct json_stream *json_stream_fail(struct command *cmd,
|
||||
/**
|
||||
* json_stream_fail_nodata - start streaming a failed json result.
|
||||
* @cmd: the command we're running.
|
||||
* @code: the error code from lightningd/jsonrpc_errors.h
|
||||
* @code: the error code from common/jsonrpc_errors.h
|
||||
* @errmsg: the error string.
|
||||
*
|
||||
* This is used by command_fail(), which doesn't add any JSON data.
|
||||
@@ -89,8 +89,6 @@ struct json_stream *json_stream_fail_nodata(struct command *cmd,
|
||||
struct json_stream *null_response(struct command *cmd);
|
||||
void command_success(struct command *cmd, struct json_stream *response);
|
||||
void command_failed(struct command *cmd, struct json_stream *result);
|
||||
void PRINTF_FMT(3, 4) command_fail(struct command *cmd, int code,
|
||||
const char *fmt, ...);
|
||||
|
||||
/* Mainly for documentation, that we plan to close this later. */
|
||||
void command_still_pending(struct command *cmd);
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* lightningd/jsonrpc_errors.h
|
||||
* Lists error codes for JSON-RPC.
|
||||
*/
|
||||
#ifndef LIGHTNING_LIGHTNINGD_JSONRPC_ERRORS_H
|
||||
#define LIGHTNING_LIGHTNINGD_JSONRPC_ERRORS_H
|
||||
#include "config.h"
|
||||
|
||||
/* Standard errors defined by JSON-RPC 2.0 standard */
|
||||
#define JSONRPC2_INVALID_REQUEST -32600
|
||||
#define JSONRPC2_METHOD_NOT_FOUND -32601
|
||||
#define JSONRPC2_INVALID_PARAMS -32602
|
||||
|
||||
/* Uncategorized error.
|
||||
* FIXME: This should be replaced in all places
|
||||
* with a specific error code, and then removed.
|
||||
*/
|
||||
#define LIGHTNINGD -1
|
||||
|
||||
/* Developer error in the parameters to param() call */
|
||||
#define PARAM_DEV_ERROR -2
|
||||
|
||||
/* Plugin returned an error */
|
||||
#define PLUGIN_ERROR -3
|
||||
|
||||
/* Errors from `pay`, `sendpay`, or `waitsendpay` commands */
|
||||
#define PAY_IN_PROGRESS 200
|
||||
#define PAY_RHASH_ALREADY_USED 201
|
||||
#define PAY_UNPARSEABLE_ONION 202
|
||||
#define PAY_DESTINATION_PERM_FAIL 203
|
||||
#define PAY_TRY_OTHER_ROUTE 204
|
||||
#define PAY_ROUTE_NOT_FOUND 205
|
||||
#define PAY_ROUTE_TOO_EXPENSIVE 206
|
||||
#define PAY_INVOICE_EXPIRED 207
|
||||
#define PAY_NO_SUCH_PAYMENT 208
|
||||
#define PAY_UNSPECIFIED_ERROR 209
|
||||
#define PAY_STOPPED_RETRYING 210
|
||||
|
||||
/* `fundchannel` or `withdraw` errors */
|
||||
#define FUND_MAX_EXCEEDED 300
|
||||
#define FUND_CANNOT_AFFORD 301
|
||||
#define FUND_OUTPUT_IS_DUST 302
|
||||
|
||||
/* Errors from `invoice` command */
|
||||
#define INVOICE_LABEL_ALREADY_EXISTS 900
|
||||
#define INVOICE_PREIMAGE_ALREADY_EXISTS 901
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_JSONRPC_ERRORS_H */
|
||||
@@ -57,6 +57,7 @@
|
||||
/*~ This is common code: routines shared by one or more executables
|
||||
* (separate daemons, or the lightning-cli program). */
|
||||
#include <common/daemon.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/utils.h>
|
||||
#include <common/version.h>
|
||||
@@ -68,7 +69,6 @@
|
||||
#include <lightningd/channel_control.h>
|
||||
#include <lightningd/connect_control.h>
|
||||
#include <lightningd/invoice.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/onchain_control.h>
|
||||
|
||||
@@ -10,17 +10,18 @@
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/tal/link/link.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/utils.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
#include <backtrace.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/daemon.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/timeout.h>
|
||||
#include <connectd/gen_connect_wire.h>
|
||||
#include <errno.h>
|
||||
@@ -12,11 +15,9 @@
|
||||
#include <hsmd/gen_hsm_wire.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/opening_control.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/channel_config.h>
|
||||
#include <common/funding_tx.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/key_derive.h>
|
||||
#include <common/param.h>
|
||||
#include <common/wallet_tx.h>
|
||||
#include <common/wire_error.h>
|
||||
#include <connectd/gen_connect_wire.h>
|
||||
@@ -16,11 +19,9 @@
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/opening_control.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <openingd/gen_opening_wire.h>
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
#include <ccan/tal/path/path.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/configdir.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/version.h>
|
||||
#include <common/wireaddr.h>
|
||||
#include <errno.h>
|
||||
@@ -19,13 +23,10 @@
|
||||
#include <lightningd/bitcoind.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/plugin.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
#include <ccan/asort/asort.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/utils.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/param.h>
|
||||
|
||||
struct param {
|
||||
const char *name;
|
||||
bool is_set;
|
||||
bool required;
|
||||
param_cbx cbx;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static bool param_add(struct param **params,
|
||||
const char *name, bool required,
|
||||
param_cbx cbx, void *arg)
|
||||
{
|
||||
#if DEVELOPER
|
||||
if (!(name && cbx && arg))
|
||||
return false;
|
||||
#endif
|
||||
struct param *last = tal_arr_expand(params);
|
||||
|
||||
last->is_set = false;
|
||||
last->name = name;
|
||||
last->required = required;
|
||||
last->cbx = cbx;
|
||||
last->arg = arg;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool make_callback(struct command *cmd,
|
||||
struct param *def,
|
||||
const char *buffer, const jsmntok_t *tok)
|
||||
{
|
||||
def->is_set = true;
|
||||
|
||||
return def->cbx(cmd, def->name, buffer, tok, def->arg);
|
||||
}
|
||||
|
||||
static bool post_check(struct command *cmd, struct param *params)
|
||||
{
|
||||
struct param *first = params;
|
||||
struct param *last = first + tal_count(params);
|
||||
|
||||
/* Make sure required params were provided. */
|
||||
while (first != last && first->required) {
|
||||
if (!first->is_set) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"missing required parameter: '%s'",
|
||||
first->name);
|
||||
return false;
|
||||
}
|
||||
first++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_by_position(struct command *cmd,
|
||||
struct param *params,
|
||||
const char *buffer,
|
||||
const jsmntok_t tokens[],
|
||||
bool allow_extra)
|
||||
{
|
||||
const jsmntok_t *tok = tokens + 1;
|
||||
const jsmntok_t *end = json_next(tokens);
|
||||
struct param *first = params;
|
||||
struct param *last = first + tal_count(params);
|
||||
|
||||
while (first != last && tok != end) {
|
||||
if (!json_tok_is_null(buffer, tok))
|
||||
if (!make_callback(cmd, first, buffer, tok))
|
||||
return NULL;
|
||||
tok = json_next(tok);
|
||||
first++;
|
||||
}
|
||||
|
||||
/* check for unexpected trailing params */
|
||||
if (!allow_extra && tok != end) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"too many parameters:"
|
||||
" got %u, expected %zu",
|
||||
tokens->size, tal_count(params));
|
||||
return false;
|
||||
}
|
||||
|
||||
return post_check(cmd, params);
|
||||
}
|
||||
|
||||
static struct param *find_param(struct param *params, const char *start,
|
||||
size_t n)
|
||||
{
|
||||
struct param *first = params;
|
||||
struct param *last = first + tal_count(params);
|
||||
|
||||
while (first != last) {
|
||||
if (strncmp(first->name, start, n) == 0)
|
||||
if (strlen(first->name) == n)
|
||||
return first;
|
||||
first++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool parse_by_name(struct command *cmd,
|
||||
struct param *params,
|
||||
const char *buffer,
|
||||
const jsmntok_t tokens[],
|
||||
bool allow_extra)
|
||||
{
|
||||
const jsmntok_t *first = tokens + 1;
|
||||
const jsmntok_t *last = json_next(tokens);
|
||||
|
||||
while (first != last) {
|
||||
struct param *p = find_param(params, buffer + first->start,
|
||||
first->end - first->start);
|
||||
if (!p) {
|
||||
if (!allow_extra) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"unknown parameter: '%.*s'",
|
||||
first->end - first->start,
|
||||
buffer + first->start);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (p->is_set) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"duplicate json names: '%s'", p->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!make_callback(cmd, p, buffer, first + 1))
|
||||
return false;
|
||||
}
|
||||
first = json_next(first + 1);
|
||||
}
|
||||
return post_check(cmd, params);
|
||||
}
|
||||
|
||||
#if DEVELOPER
|
||||
static int comp_by_name(const struct param *a, const struct param *b,
|
||||
void *unused)
|
||||
{
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static int comp_by_arg(const struct param *a, const struct param *b,
|
||||
void *unused)
|
||||
{
|
||||
/* size_t could be larger than int: don't turn a 4bn difference into 0 */
|
||||
if (a->arg > b->arg)
|
||||
return 1;
|
||||
else if (a->arg < b->arg)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This comparator is a bit different, but works well.
|
||||
* Return 0 if @a is optional and @b is required. Otherwise return 1.
|
||||
*/
|
||||
static int comp_req_order(const struct param *a, const struct param *b,
|
||||
void *unused)
|
||||
{
|
||||
if (!a->required && b->required)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure 2 sequential items in @params are not equal (based on
|
||||
* provided comparator).
|
||||
*/
|
||||
static bool check_distinct(struct param *params,
|
||||
int (*compar) (const struct param *a,
|
||||
const struct param *b, void *unused))
|
||||
{
|
||||
struct param *first = params;
|
||||
struct param *last = first + tal_count(params);
|
||||
first++;
|
||||
while (first != last) {
|
||||
if (compar(first - 1, first, NULL) == 0)
|
||||
return false;
|
||||
first++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_unique(struct param *copy,
|
||||
int (*compar) (const struct param *a,
|
||||
const struct param *b, void *unused))
|
||||
{
|
||||
asort(copy, tal_count(copy), compar, NULL);
|
||||
return check_distinct(copy, compar);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify consistent internal state.
|
||||
*/
|
||||
static bool check_params(struct param *params)
|
||||
{
|
||||
if (tal_count(params) < 2)
|
||||
return true;
|
||||
|
||||
/* make sure there are no required params following optional */
|
||||
if (!check_distinct(params, comp_req_order))
|
||||
return false;
|
||||
|
||||
/* duplicate so we can sort */
|
||||
struct param *copy = tal_dup_arr(params, struct param,
|
||||
params, tal_count(params), 0);
|
||||
|
||||
/* check for repeated names and args */
|
||||
if (!check_unique(copy, comp_by_name))
|
||||
return false;
|
||||
if (!check_unique(copy, comp_by_arg))
|
||||
return false;
|
||||
|
||||
tal_free(copy);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *param_usage(const tal_t *ctx,
|
||||
const struct param *params)
|
||||
{
|
||||
char *usage = tal_strdup(ctx, "");
|
||||
for (size_t i = 0; i < tal_count(params); i++) {
|
||||
if (i != 0)
|
||||
tal_append_fmt(&usage, " ");
|
||||
if (params[i].required)
|
||||
tal_append_fmt(&usage, "%s", params[i].name);
|
||||
else
|
||||
tal_append_fmt(&usage, "[%s]", params[i].name);
|
||||
}
|
||||
return usage;
|
||||
}
|
||||
|
||||
static bool param_arr(struct command *cmd, const char *buffer,
|
||||
const jsmntok_t tokens[],
|
||||
struct param *params,
|
||||
bool allow_extra)
|
||||
{
|
||||
#if DEVELOPER
|
||||
if (!check_params(params)) {
|
||||
command_fail(cmd, PARAM_DEV_ERROR, "developer error: check_params");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (tokens->type == JSMN_ARRAY)
|
||||
return parse_by_position(cmd, params, buffer, tokens, allow_extra);
|
||||
else if (tokens->type == JSMN_OBJECT)
|
||||
return parse_by_name(cmd, params, buffer, tokens, allow_extra);
|
||||
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Expected array or object for params");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool param(struct command *cmd, const char *buffer,
|
||||
const jsmntok_t tokens[], ...)
|
||||
{
|
||||
struct param *params = tal_arr(cmd, struct param, 0);
|
||||
const char *name;
|
||||
va_list ap;
|
||||
bool allow_extra = false;
|
||||
|
||||
va_start(ap, tokens);
|
||||
while ((name = va_arg(ap, const char *)) != NULL) {
|
||||
bool required = va_arg(ap, int);
|
||||
param_cbx cbx = va_arg(ap, param_cbx);
|
||||
void *arg = va_arg(ap, void *);
|
||||
if (streq(name, "")) {
|
||||
allow_extra = true;
|
||||
continue;
|
||||
}
|
||||
if (!param_add(¶ms, name, required, cbx, arg)) {
|
||||
command_fail(cmd, PARAM_DEV_ERROR,
|
||||
"developer error: param_add %s", name);
|
||||
va_end(ap);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (command_usage_only(cmd)) {
|
||||
command_set_usage(cmd, param_usage(cmd, params));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Always return false if we're simply checking command parameters;
|
||||
* normally this returns true if all parameters are valid. */
|
||||
return param_arr(cmd, buffer, tokens, params, allow_extra)
|
||||
&& !command_check_only(cmd);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_PARAM_H
|
||||
#define LIGHTNING_LIGHTNINGD_PARAM_H
|
||||
#include "config.h"
|
||||
|
||||
/*~ Greetings adventurer!
|
||||
*
|
||||
* Do you want to automatically validate json input and unmarshall it into
|
||||
* local variables, all using typesafe callbacks? And on error,
|
||||
* call command_fail with a proper error message? Then you've come to the
|
||||
* right place!
|
||||
*
|
||||
* Here is a simple example of using the system:
|
||||
*
|
||||
* unsigned *cltv;
|
||||
* u64 *msatoshi;
|
||||
* const jsmntok_t *note;
|
||||
* u64 *expiry;
|
||||
*
|
||||
* if (!param(cmd, buffer, params,
|
||||
* p_req("cltv", json_tok_number, &cltv),
|
||||
* p_opt("msatoshi", json_tok_u64, &msatoshi),
|
||||
* p_opt("note", json_tok_tok, ¬e),
|
||||
* p_opt_def("expiry", json_tok_u64, &expiry, 3600),
|
||||
* NULL))
|
||||
* return;
|
||||
*
|
||||
* If param() returns true then you're good to go.
|
||||
*
|
||||
* All the command handlers throughout the code use this system.
|
||||
* json_invoice() is a great example. The common callbacks can be found in
|
||||
* lightningd/json.c. Use them directly or feel free to write your own.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parse the json tokens. @params can be an array of values or an object
|
||||
* of named values.
|
||||
*/
|
||||
bool param(struct command *cmd, const char *buffer,
|
||||
const jsmntok_t params[], ...);
|
||||
|
||||
/*
|
||||
* The callback signature. Callbacks must return true on success. On failure they
|
||||
* must call comand_fail and return false.
|
||||
*/
|
||||
typedef bool(*param_cbx)(struct command *cmd,
|
||||
const char *name,
|
||||
const char *buffer,
|
||||
const jsmntok_t *tok,
|
||||
void **arg);
|
||||
|
||||
/*
|
||||
* Add a required parameter.
|
||||
*/
|
||||
#define p_req(name, cbx, arg) \
|
||||
name"", \
|
||||
true, \
|
||||
(cbx), \
|
||||
(arg) + 0*sizeof((cbx)((struct command *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const jsmntok_t *)NULL, \
|
||||
(arg)) == true)
|
||||
|
||||
/*
|
||||
* Add an optional parameter. *arg is set to NULL if it isn't found.
|
||||
*/
|
||||
#define p_opt(name, cbx, arg) \
|
||||
name"", \
|
||||
false, \
|
||||
(cbx), \
|
||||
({ *arg = NULL; \
|
||||
(arg) + 0*sizeof((cbx)((struct command *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const jsmntok_t *)NULL, \
|
||||
(arg)) == true); })
|
||||
|
||||
/*
|
||||
* Add an optional parameter. *arg is set to @def if it isn't found.
|
||||
*/
|
||||
#define p_opt_def(name, cbx, arg, def) \
|
||||
name"", \
|
||||
false, \
|
||||
(cbx), \
|
||||
({ (*arg) = tal((cmd), typeof(**arg)); \
|
||||
(**arg) = (def); \
|
||||
(arg) + 0*sizeof((cbx)((struct command *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const char *)NULL, \
|
||||
(const jsmntok_t *)NULL, \
|
||||
(arg)) == true); })
|
||||
|
||||
/* Special flag for 'check' which allows any parameters. */
|
||||
#define p_opt_any() "", false, NULL, NULL
|
||||
#endif /* LIGHTNING_LIGHTNINGD_PARAM_H */
|
||||
@@ -2,16 +2,17 @@
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/bolt11.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <common/timeout.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
#include <lightningd/subd.h>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <common/bolt11.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/type_to_string.h>
|
||||
@@ -12,10 +15,8 @@
|
||||
#include <gossipd/routing.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
#include <common/dev_disconnect.h>
|
||||
#include <common/features.h>
|
||||
#include <common/initial_commit_tx.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/key_derive.h>
|
||||
#include <common/param.h>
|
||||
#include <common/status.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/version.h>
|
||||
@@ -33,13 +36,11 @@
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/memdump.h>
|
||||
#include <lightningd/onchain_control.h>
|
||||
#include <lightningd/opening_control.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
#include <unistd.h>
|
||||
#include <wally_bip32.h>
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_escaped.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/overflows.h>
|
||||
#include <common/param.h>
|
||||
#include <common/sphinx.h>
|
||||
#include <common/timeout.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/htlc_end.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/json_escaped.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/pay.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <common/sphinx.h>
|
||||
#include <common/utils.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/htlc_end.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/ping.h>
|
||||
#include <lightningd/subd.h>
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
#include <ccan/tal/path/path.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/utf8/utf8.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/param.h>
|
||||
#include <common/timeout.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -13,6 +13,7 @@ LIGHTNINGD_TEST_COMMON_OBJS := \
|
||||
common/htlc_state.o \
|
||||
common/io_lock.o \
|
||||
common/json.o \
|
||||
common/json_escaped.o \
|
||||
common/key_derive.o \
|
||||
common/pseudorand.o \
|
||||
common/memleak.o \
|
||||
|
||||
@@ -91,9 +91,6 @@ void hsm_init(struct lightningd *ld UNNEEDED)
|
||||
/* Generated stub for htlcs_notify_new_block */
|
||||
void htlcs_notify_new_block(struct lightningd *ld UNNEEDED, u32 height UNNEEDED)
|
||||
{ fprintf(stderr, "htlcs_notify_new_block called!\n"); abort(); }
|
||||
/* Generated stub for json_escape */
|
||||
struct json_escaped *json_escape(const tal_t *ctx UNNEEDED, const char *str TAKES UNNEEDED)
|
||||
{ fprintf(stderr, "json_escape called!\n"); abort(); }
|
||||
/* Generated stub for jsonrpc_listen */
|
||||
void jsonrpc_listen(struct jsonrpc *rpc UNNEEDED, struct lightningd *ld UNNEEDED)
|
||||
{ fprintf(stderr, "jsonrpc_listen called!\n"); abort(); }
|
||||
|
||||
@@ -164,9 +164,6 @@ void json_array_end(struct json_stream *js UNNEEDED)
|
||||
/* Generated stub for json_array_start */
|
||||
void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED)
|
||||
{ fprintf(stderr, "json_array_start called!\n"); abort(); }
|
||||
/* Generated stub for json_escape */
|
||||
struct json_escaped *json_escape(const tal_t *ctx UNNEEDED, const char *str TAKES UNNEEDED)
|
||||
{ fprintf(stderr, "json_escape called!\n"); abort(); }
|
||||
/* Generated stub for json_object_end */
|
||||
void json_object_end(struct json_stream *js UNNEEDED)
|
||||
{ fprintf(stderr, "json_object_end called!\n"); abort(); }
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "../json_escaped.c"
|
||||
#include <assert.h>
|
||||
#include <common/utils.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void test_json_partial(void)
|
||||
{
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
|
||||
assert(streq(json_partial_escape(ctx, "\\")->s, "\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\")->s, "\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\\\")->s, "\\\\\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\\\\\\")->s, "\\\\\\\\"));
|
||||
assert(streq(json_partial_escape(ctx, "\\n")->s, "\\n"));
|
||||
assert(streq(json_partial_escape(ctx, "\n")->s, "\\n"));
|
||||
assert(streq(json_partial_escape(ctx, "\\\"")->s, "\\\""));
|
||||
assert(streq(json_partial_escape(ctx, "\"")->s, "\\\""));
|
||||
assert(streq(json_partial_escape(ctx, "\\t")->s, "\\t"));
|
||||
assert(streq(json_partial_escape(ctx, "\t")->s, "\\t"));
|
||||
assert(streq(json_partial_escape(ctx, "\\b")->s, "\\b"));
|
||||
assert(streq(json_partial_escape(ctx, "\b")->s, "\\b"));
|
||||
assert(streq(json_partial_escape(ctx, "\\r")->s, "\\r"));
|
||||
assert(streq(json_partial_escape(ctx, "\r")->s, "\\r"));
|
||||
assert(streq(json_partial_escape(ctx, "\\f")->s, "\\f"));
|
||||
assert(streq(json_partial_escape(ctx, "\f")->s, "\\f"));
|
||||
/* You're allowed to escape / according to json.org. */
|
||||
assert(streq(json_partial_escape(ctx, "\\/")->s, "\\/"));
|
||||
assert(streq(json_partial_escape(ctx, "/")->s, "/"));
|
||||
|
||||
assert(streq(json_partial_escape(ctx, "\\u0FFF")->s, "\\u0FFF"));
|
||||
assert(streq(json_partial_escape(ctx, "\\u0FFFx")->s, "\\u0FFFx"));
|
||||
|
||||
/* Unknown escapes should be escaped. */
|
||||
assert(streq(json_partial_escape(ctx, "\\x")->s, "\\\\x"));
|
||||
tal_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup_locale();
|
||||
|
||||
test_json_partial();
|
||||
assert(!taken_any());
|
||||
take_cleanup();
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "../json_escaped.c"
|
||||
#include "../json_stream.c"
|
||||
#include "../jsonrpc.c"
|
||||
#include "../json.c"
|
||||
@@ -26,6 +25,21 @@ char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr
|
||||
bool json_feerate_estimate(struct command *cmd UNNEEDED,
|
||||
u32 **feerate_per_kw UNNEEDED, enum feerate feerate UNNEEDED)
|
||||
{ fprintf(stderr, "json_feerate_estimate called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_number */
|
||||
bool json_tok_number(struct command *cmd UNNEEDED, const char *name UNNEEDED,
|
||||
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
unsigned int **num UNNEEDED)
|
||||
{ fprintf(stderr, "json_tok_number called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_sha256 */
|
||||
bool json_tok_sha256(struct command *cmd UNNEEDED, const char *name UNNEEDED,
|
||||
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
struct sha256 **hash UNNEEDED)
|
||||
{ fprintf(stderr, "json_tok_sha256 called!\n"); abort(); }
|
||||
/* Generated stub for json_tok_tok */
|
||||
bool json_tok_tok(struct command *cmd UNNEEDED, const char *name UNNEEDED,
|
||||
const char *buffer UNNEEDED, const jsmntok_t * tok UNNEEDED,
|
||||
const jsmntok_t **out UNNEEDED)
|
||||
{ fprintf(stderr, "json_tok_tok called!\n"); abort(); }
|
||||
/* Generated stub for log_ */
|
||||
void log_(struct log *log UNNEEDED, enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...)
|
||||
|
||||
|
||||
@@ -1,602 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "../json.c"
|
||||
#include "../json_escaped.c"
|
||||
#include "../json_stream.c"
|
||||
#include "../param.c"
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <common/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
char *fail_msg = NULL;
|
||||
bool failed = false;
|
||||
|
||||
static bool check_fail(void) {
|
||||
if (!failed)
|
||||
return false;
|
||||
failed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct command *cmd;
|
||||
|
||||
void command_fail(struct command *cmd, int code, const char *fmt, ...)
|
||||
{
|
||||
failed = true;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fail_msg = tal_vfmt(cmd, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* AUTOGENERATED MOCKS START */
|
||||
/* Generated stub for feerate_from_style */
|
||||
u32 feerate_from_style(u32 feerate UNNEEDED, enum feerate_style style UNNEEDED)
|
||||
{ fprintf(stderr, "feerate_from_style called!\n"); abort(); }
|
||||
/* Generated stub for feerate_name */
|
||||
const char *feerate_name(enum feerate feerate UNNEEDED)
|
||||
{ fprintf(stderr, "feerate_name called!\n"); abort(); }
|
||||
/* Generated stub for fmt_wireaddr_without_port */
|
||||
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
|
||||
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
|
||||
/* Generated stub for json_feerate_estimate */
|
||||
bool json_feerate_estimate(struct command *cmd UNNEEDED,
|
||||
u32 **feerate_per_kw UNNEEDED, enum feerate feerate UNNEEDED)
|
||||
{ fprintf(stderr, "json_feerate_estimate called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
void command_set_usage(struct command *cmd, const char *usage)
|
||||
{
|
||||
cmd->usage = usage;
|
||||
}
|
||||
|
||||
bool command_usage_only(const struct command *cmd)
|
||||
{
|
||||
return cmd->mode == CMD_USAGE;
|
||||
}
|
||||
|
||||
bool command_check_only(const struct command *cmd)
|
||||
{
|
||||
return cmd->mode == CMD_CHECK;
|
||||
}
|
||||
|
||||
struct json {
|
||||
jsmntok_t *toks;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
static void convert_quotes(char *first)
|
||||
{
|
||||
while (*first != '\0') {
|
||||
if (*first == '\'')
|
||||
*first = '"';
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct json *json_parse(const tal_t * ctx, const char *str)
|
||||
{
|
||||
struct json *j = tal(ctx, struct json);
|
||||
j->buffer = tal_strdup(j, str);
|
||||
convert_quotes(j->buffer);
|
||||
|
||||
j->toks = tal_arr(j, jsmntok_t, 50);
|
||||
assert(j->toks);
|
||||
jsmn_parser parser;
|
||||
|
||||
again:
|
||||
jsmn_init(&parser);
|
||||
int ret = jsmn_parse(&parser, j->buffer, strlen(j->buffer), j->toks,
|
||||
tal_count(j->toks));
|
||||
if (ret == JSMN_ERROR_NOMEM) {
|
||||
tal_resize(&j->toks, tal_count(j->toks) * 2);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
assert(0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
static void zero_params(void)
|
||||
{
|
||||
struct json *j = json_parse(cmd, "{}");
|
||||
assert(param(cmd, j->buffer, j->toks, NULL));
|
||||
|
||||
j = json_parse(cmd, "[]");
|
||||
assert(param(cmd, j->buffer, j->toks, NULL));
|
||||
}
|
||||
|
||||
struct sanity {
|
||||
char *str;
|
||||
bool failed;
|
||||
int ival;
|
||||
double dval;
|
||||
char *fail_str;
|
||||
};
|
||||
|
||||
struct sanity buffers[] = {
|
||||
// pass
|
||||
{"['42', '3.15']", false, 42, 3.15, NULL},
|
||||
{"{ 'u64' : '42', 'double' : '3.15' }", false, 42, 3.15, NULL},
|
||||
|
||||
// fail
|
||||
{"{'u64':'42', 'double':'3.15', 'extra':'stuff'}", true, 0, 0,
|
||||
"unknown parameter"},
|
||||
{"['42', '3.15', 'stuff']", true, 0, 0, "too many"},
|
||||
{"['42', '3.15', 'null']", true, 0, 0, "too many"},
|
||||
|
||||
// not enough
|
||||
{"{'u64':'42'}", true, 0, 0, "missing required"},
|
||||
{"['42']", true, 0, 0, "missing required"},
|
||||
|
||||
// fail wrong type
|
||||
{"{'u64':'hello', 'double':'3.15'}", true, 0, 0, "be an unsigned 64"},
|
||||
{"['3.15', '3.15', 'stuff']", true, 0, 0, "integer"},
|
||||
};
|
||||
|
||||
static void stest(const struct json *j, struct sanity *b)
|
||||
{
|
||||
u64 *ival;
|
||||
double *dval;
|
||||
if (!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", json_tok_u64, &ival),
|
||||
p_req("double", json_tok_double, &dval), NULL)) {
|
||||
assert(check_fail());
|
||||
assert(b->failed == true);
|
||||
if (!strstr(fail_msg, b->fail_str)) {
|
||||
printf("%s != %s\n", fail_msg, b->fail_str);
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
assert(!check_fail());
|
||||
assert(b->failed == false);
|
||||
assert(*ival == 42);
|
||||
assert(*dval > 3.1499 && b->dval < 3.1501);
|
||||
}
|
||||
}
|
||||
|
||||
static void sanity(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(buffers); ++i) {
|
||||
struct json *j = json_parse(cmd, buffers[i].str);
|
||||
assert(j->toks->type == JSMN_OBJECT
|
||||
|| j->toks->type == JSMN_ARRAY);
|
||||
stest(j, &buffers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure toks are passed through correctly, and also make sure
|
||||
* optional missing toks are set to NULL.
|
||||
*/
|
||||
static void tok_tok(void)
|
||||
{
|
||||
{
|
||||
unsigned int n;
|
||||
const jsmntok_t *tok = NULL;
|
||||
struct json *j = json_parse(cmd, "{ 'satoshi', '546' }");
|
||||
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_req("satoshi", json_tok_tok, &tok), NULL));
|
||||
assert(tok);
|
||||
assert(json_to_number(j->buffer, tok, &n));
|
||||
assert(n == 546);
|
||||
}
|
||||
// again with missing optional parameter
|
||||
{
|
||||
/* make sure it is *not* NULL */
|
||||
const jsmntok_t *tok = (const jsmntok_t *) 65535;
|
||||
|
||||
struct json *j = json_parse(cmd, "{}");
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_opt("satoshi", json_tok_tok, &tok), NULL));
|
||||
|
||||
/* make sure it *is* NULL */
|
||||
assert(tok == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for valid but duplicate json name-value pairs */
|
||||
static void dup_names(void)
|
||||
{
|
||||
struct json *j =
|
||||
json_parse(cmd,
|
||||
"{ 'u64' : '42', 'u64' : '43', 'double' : '3.15' }");
|
||||
|
||||
u64 *i;
|
||||
double *d;
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", json_tok_u64, &i),
|
||||
p_req("double", json_tok_double, &d), NULL));
|
||||
}
|
||||
|
||||
static void null_params(void)
|
||||
{
|
||||
uint64_t **intptrs = tal_arr(cmd, uint64_t *, 7);
|
||||
/* no null params */
|
||||
struct json *j =
|
||||
json_parse(cmd, "[ '10', '11', '12', '13', '14', '15', '16']");
|
||||
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_req("0", json_tok_u64, &intptrs[0]),
|
||||
p_req("1", json_tok_u64, &intptrs[1]),
|
||||
p_req("2", json_tok_u64, &intptrs[2]),
|
||||
p_req("3", json_tok_u64, &intptrs[3]),
|
||||
p_opt_def("4", json_tok_u64, &intptrs[4], 999),
|
||||
p_opt("5", json_tok_u64, &intptrs[5]),
|
||||
p_opt("6", json_tok_u64, &intptrs[6]),
|
||||
NULL));
|
||||
for (int i = 0; i < tal_count(intptrs); ++i) {
|
||||
assert(intptrs[i]);
|
||||
assert(*intptrs[i] == i + 10);
|
||||
}
|
||||
|
||||
/* missing at end */
|
||||
j = json_parse(cmd, "[ '10', '11', '12', '13', '14']");
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_req("0", json_tok_u64, &intptrs[0]),
|
||||
p_req("1", json_tok_u64, &intptrs[1]),
|
||||
p_req("2", json_tok_u64, &intptrs[2]),
|
||||
p_req("3", json_tok_u64, &intptrs[3]),
|
||||
p_opt("4", json_tok_u64, &intptrs[4]),
|
||||
p_opt("5", json_tok_u64, &intptrs[5]),
|
||||
p_opt_def("6", json_tok_u64, &intptrs[6], 888),
|
||||
NULL));
|
||||
assert(*intptrs[0] == 10);
|
||||
assert(*intptrs[1] == 11);
|
||||
assert(*intptrs[2] == 12);
|
||||
assert(*intptrs[3] == 13);
|
||||
assert(*intptrs[4] == 14);
|
||||
assert(!intptrs[5]);
|
||||
assert(*intptrs[6] == 888);
|
||||
}
|
||||
|
||||
static void no_params(void)
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[]");
|
||||
assert(param(cmd, j->buffer, j->toks, NULL));
|
||||
|
||||
j = json_parse(cmd, "[ 'unexpected' ]");
|
||||
assert(!param(cmd, j->buffer, j->toks, NULL));
|
||||
}
|
||||
|
||||
|
||||
#if DEVELOPER
|
||||
/*
|
||||
* Check to make sure there are no programming mistakes.
|
||||
*/
|
||||
static void bad_programmer(void)
|
||||
{
|
||||
u64 *ival;
|
||||
u64 *ival2;
|
||||
double *dval;
|
||||
struct json *j = json_parse(cmd, "[ '25', '546', '26' ]");
|
||||
|
||||
/* check for repeated names */
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("repeat", json_tok_u64, &ival),
|
||||
p_req("double", json_tok_double, &dval),
|
||||
p_req("repeat", json_tok_u64, &ival2), NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("repeat", json_tok_u64, &ival),
|
||||
p_req("double", json_tok_double, &dval),
|
||||
p_req("repeat", json_tok_u64, &ival), NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", json_tok_u64, &ival),
|
||||
p_req("repeat", json_tok_double, &dval),
|
||||
p_req("repeat", json_tok_double, &dval), NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
|
||||
/* check for repeated arguments */
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", json_tok_u64, &ival),
|
||||
p_req("repeated-arg", json_tok_u64, &ival), NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", (param_cbx) NULL, NULL), NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
|
||||
/* Add required param after optional */
|
||||
j = json_parse(cmd, "[ '25', '546', '26', '1.1' ]");
|
||||
unsigned int *msatoshi;
|
||||
double *riskfactor;
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("u64", json_tok_u64, &ival),
|
||||
p_req("double", json_tok_double, &dval),
|
||||
p_opt_def("msatoshi", json_tok_number, &msatoshi, 100),
|
||||
p_req("riskfactor", json_tok_double, &riskfactor), NULL));
|
||||
assert(*msatoshi);
|
||||
assert(*msatoshi == 100);
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "developer error"));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_members(struct param **params,
|
||||
char **obj,
|
||||
char **arr, unsigned int **ints)
|
||||
{
|
||||
for (int i = 0; i < tal_count(ints); ++i) {
|
||||
const char *name = tal_fmt(*params, "%i", i);
|
||||
if (i != 0) {
|
||||
tal_append_fmt(obj, ", ");
|
||||
tal_append_fmt(arr, ", ");
|
||||
}
|
||||
tal_append_fmt(obj, "\"%i\" : %i", i, i);
|
||||
tal_append_fmt(arr, "%i", i);
|
||||
param_add(params, name, true,
|
||||
typesafe_cb_preargs(bool, void **,
|
||||
json_tok_number,
|
||||
&ints[i],
|
||||
struct command *,
|
||||
const char *,
|
||||
const char *,
|
||||
const jsmntok_t *),
|
||||
&ints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A roundabout way of initializing an array of ints to:
|
||||
* ints[0] = 0, ints[1] = 1, ... ints[499] = 499
|
||||
*/
|
||||
static void five_hundred_params(void)
|
||||
{
|
||||
struct param *params = tal_arr(NULL, struct param, 0);
|
||||
|
||||
unsigned int **ints = tal_arr(params, unsigned int*, 500);
|
||||
char *obj = tal_fmt(params, "{ ");
|
||||
char *arr = tal_fmt(params, "[ ");
|
||||
add_members(¶ms, &obj, &arr, ints);
|
||||
tal_append_fmt(&obj, "}");
|
||||
tal_append_fmt(&arr, "]");
|
||||
|
||||
/* first test object version */
|
||||
struct json *j = json_parse(params, obj);
|
||||
assert(param_arr(cmd, j->buffer, j->toks, params, false));
|
||||
for (int i = 0; i < tal_count(ints); ++i) {
|
||||
assert(ints[i]);
|
||||
assert(*ints[i] == i);
|
||||
*ints[i] = 65535;
|
||||
}
|
||||
|
||||
/* now test array */
|
||||
j = json_parse(params, arr);
|
||||
assert(param_arr(cmd, j->buffer, j->toks, params, false));
|
||||
for (int i = 0; i < tal_count(ints); ++i) {
|
||||
assert(*ints[i] == i);
|
||||
}
|
||||
|
||||
tal_free(params);
|
||||
}
|
||||
|
||||
static void sendpay(void)
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[ 'A', '123', 'hello there' '547']");
|
||||
|
||||
const jsmntok_t *routetok, *note;
|
||||
u64 *msatoshi;
|
||||
unsigned *cltv;
|
||||
|
||||
if (!param(cmd, j->buffer, j->toks,
|
||||
p_req("route", json_tok_tok, &routetok),
|
||||
p_req("cltv", json_tok_number, &cltv),
|
||||
p_opt("note", json_tok_tok, ¬e),
|
||||
p_opt("msatoshi", json_tok_u64, &msatoshi),
|
||||
NULL))
|
||||
assert(false);
|
||||
|
||||
assert(note);
|
||||
assert(!strncmp("hello there", j->buffer + note->start,
|
||||
note->end - note->start));
|
||||
assert(msatoshi);
|
||||
assert(*msatoshi == 547);
|
||||
}
|
||||
|
||||
static void sendpay_nulltok(void)
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[ 'A', '123']");
|
||||
|
||||
const jsmntok_t *routetok, *note = (void *) 65535;
|
||||
u64 *msatoshi;
|
||||
unsigned *cltv;
|
||||
|
||||
if (!param(cmd, j->buffer, j->toks,
|
||||
p_req("route", json_tok_tok, &routetok),
|
||||
p_req("cltv", json_tok_number, &cltv),
|
||||
p_opt("note", json_tok_tok, ¬e),
|
||||
p_opt("msatoshi", json_tok_u64, &msatoshi),
|
||||
NULL))
|
||||
assert(false);
|
||||
|
||||
assert(note == NULL);
|
||||
assert(msatoshi == NULL);
|
||||
}
|
||||
|
||||
static void advanced(void)
|
||||
{
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[ 'lightning', 24, 'tok', 543 ]");
|
||||
|
||||
struct json_escaped *label;
|
||||
u64 *msat;
|
||||
u64 *msat_opt1, *msat_opt2;
|
||||
const jsmntok_t *tok;
|
||||
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_req("description", json_tok_label, &label),
|
||||
p_req("msat", json_tok_msat, &msat),
|
||||
p_req("tok", json_tok_tok, &tok),
|
||||
p_opt("msat_opt1", json_tok_msat, &msat_opt1),
|
||||
p_opt("msat_opt2", json_tok_msat, &msat_opt2),
|
||||
NULL));
|
||||
assert(label != NULL);
|
||||
assert(streq(label->s, "lightning"));
|
||||
assert(*msat == 24);
|
||||
assert(tok);
|
||||
assert(msat_opt1);
|
||||
assert(*msat_opt1 == 543);
|
||||
assert(msat_opt2 == NULL);
|
||||
}
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[ 3 'foo' ]");
|
||||
struct json_escaped *label, *foo;
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_req("label", json_tok_label, &label),
|
||||
p_opt("foo", json_tok_label, &foo),
|
||||
NULL));
|
||||
assert(streq(label->s, "3"));
|
||||
assert(streq(foo->s, "foo"));
|
||||
}
|
||||
{
|
||||
u64 *msat;
|
||||
u64 *msat2;
|
||||
struct json *j = json_parse(cmd, "[ 3 ]");
|
||||
assert(param(cmd, j->buffer, j->toks,
|
||||
p_opt_def("msat", json_tok_msat, &msat, 23),
|
||||
p_opt_def("msat2", json_tok_msat, &msat2, 53),
|
||||
NULL));
|
||||
assert(*msat == 3);
|
||||
assert(msat2);
|
||||
assert(*msat2 == 53);
|
||||
}
|
||||
}
|
||||
|
||||
static void advanced_fail(void)
|
||||
{
|
||||
{
|
||||
struct json *j = json_parse(cmd, "[ 'anyx' ]");
|
||||
u64 *msat;
|
||||
assert(!param(cmd, j->buffer, j->toks,
|
||||
p_req("msat", json_tok_msat, &msat),
|
||||
NULL));
|
||||
assert(check_fail());
|
||||
assert(strstr(fail_msg, "'msat' should be a positive"
|
||||
" number or 'any', not 'anyx'"));
|
||||
}
|
||||
}
|
||||
|
||||
#define test_cb(cb, T, json_, value, pass) \
|
||||
{ \
|
||||
struct json *j = json_parse(cmd, json_); \
|
||||
T *v; \
|
||||
bool ret = cb(cmd, "name", j->buffer, j->toks + 1, &v); \
|
||||
assert(ret == pass); \
|
||||
if (ret) { \
|
||||
assert(v); \
|
||||
assert(*v == value); \
|
||||
} \
|
||||
}
|
||||
|
||||
static void json_tok_tests(void)
|
||||
{
|
||||
test_cb(json_tok_bool, bool, "[ true ]", true, true);
|
||||
test_cb(json_tok_bool, bool, "[ false ]", false, true);
|
||||
test_cb(json_tok_bool, bool, "[ tru ]", false, false);
|
||||
test_cb(json_tok_bool, bool, "[ 1 ]", false, false);
|
||||
|
||||
test_cb(json_tok_percent, double, "[ -0.01 ]", 0, false);
|
||||
test_cb(json_tok_percent, double, "[ 0.00 ]", 0, true);
|
||||
test_cb(json_tok_percent, double, "[ 1 ]", 1, true);
|
||||
test_cb(json_tok_percent, double, "[ 1.1 ]", 1.1, true);
|
||||
test_cb(json_tok_percent, double, "[ 1.01 ]", 1.01, true);
|
||||
test_cb(json_tok_percent, double, "[ 99.99 ]", 99.99, true);
|
||||
test_cb(json_tok_percent, double, "[ 100.0 ]", 100, true);
|
||||
test_cb(json_tok_percent, double, "[ 100.001 ]", 100.001, true);
|
||||
test_cb(json_tok_percent, double, "[ 1000 ]", 1000, true);
|
||||
test_cb(json_tok_percent, double, "[ 'wow' ]", 0, false);
|
||||
}
|
||||
|
||||
static void test_invoice(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
u64 *msatoshi_val;
|
||||
struct json_escaped *label_val;
|
||||
const char *desc_val;
|
||||
u64 *expiry;
|
||||
const jsmntok_t *fallbacks;
|
||||
const jsmntok_t *preimagetok;
|
||||
|
||||
assert(cmd->mode == CMD_USAGE);
|
||||
if(!param(cmd, buffer, params,
|
||||
p_req("msatoshi", json_tok_msat, &msatoshi_val),
|
||||
p_req("label", json_tok_label, &label_val),
|
||||
p_req("description", json_tok_escaped_string, &desc_val),
|
||||
p_opt("expiry", json_tok_u64, &expiry),
|
||||
p_opt("fallbacks", json_tok_array, &fallbacks),
|
||||
p_opt("preimage", json_tok_tok, &preimagetok), NULL))
|
||||
return;
|
||||
|
||||
/* should not be here since we are in the mode of CMD_USAGE
|
||||
* and it always returns false. */
|
||||
abort();
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
/* Do this to simulate a call to our pretend handler (test_invoice) */
|
||||
struct json_command invoice_command = {
|
||||
"invoice",
|
||||
test_invoice,
|
||||
"",
|
||||
false,
|
||||
""
|
||||
};
|
||||
|
||||
cmd->mode = CMD_USAGE;
|
||||
cmd->json_cmd = &invoice_command;
|
||||
|
||||
cmd->json_cmd->dispatch(cmd, NULL, NULL, NULL);
|
||||
|
||||
assert(streq(cmd->usage,
|
||||
"msatoshi label description "
|
||||
"[expiry] [fallbacks] [preimage]"));
|
||||
|
||||
cmd->mode = CMD_NORMAL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup_locale();
|
||||
setup_tmpctx();
|
||||
cmd = tal(tmpctx, struct command);
|
||||
cmd->mode = CMD_NORMAL;
|
||||
fail_msg = tal_arr(cmd, char, 10000);
|
||||
|
||||
zero_params();
|
||||
sanity();
|
||||
tok_tok();
|
||||
null_params();
|
||||
no_params();
|
||||
#if DEVELOPER
|
||||
bad_programmer();
|
||||
#endif
|
||||
dup_names();
|
||||
five_hundred_params();
|
||||
sendpay();
|
||||
sendpay_nulltok();
|
||||
advanced();
|
||||
advanced_fail();
|
||||
json_tok_tests();
|
||||
usage();
|
||||
|
||||
tal_free(tmpctx);
|
||||
printf("run-params ok\n");
|
||||
}
|
||||
Reference in New Issue
Block a user