diff --git a/cli/Makefile b/cli/Makefile index 635a8d4e9..fcbf84a6a 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -8,8 +8,7 @@ ALL_PROGRAMS += cli/lightning-cli LIGHTNING_CLI_COMMON_OBJS := \ bitcoin/chainparams.o \ common/configdir.o \ - common/json.o \ - common/json_stream.o \ + common/json_parse_simple.o \ common/status_levels.o \ common/utils.o \ common/version.o diff --git a/cli/test/Makefile b/cli/test/Makefile index e49837f22..3b5a800fe 100644 --- a/cli/test/Makefile +++ b/cli/test/Makefile @@ -12,7 +12,7 @@ CLI_TEST_COMMON_OBJS := \ common/configdir.o \ common/daemon_conn.o \ common/htlc_state.o \ - common/json.o \ + common/json_parse_simple.o \ common/pseudorand.o \ common/memleak.o \ common/msg_queue.o \ diff --git a/cli/test/run-human-mode.c b/cli/test/run-human-mode.c index e88b220a3..078af8465 100644 --- a/cli/test/run-human-mode.c +++ b/cli/test/run-human-mode.c @@ -78,16 +78,6 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for log_level_name */ const char *log_level_name(enum log_level level UNNEEDED) { fprintf(stderr, "log_level_name called!\n"); abort(); } diff --git a/cli/test/run-large-input.c b/cli/test/run-large-input.c index 1bb043bf1..bbba588bd 100644 --- a/cli/test/run-large-input.c +++ b/cli/test/run-large-input.c @@ -78,16 +78,6 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for log_level_name */ const char *log_level_name(enum log_level level UNNEEDED) { fprintf(stderr, "log_level_name called!\n"); abort(); } diff --git a/cli/test/run-remove-hint.c b/cli/test/run-remove-hint.c index 3246db8a3..e416a2973 100644 --- a/cli/test/run-remove-hint.c +++ b/cli/test/run-remove-hint.c @@ -81,16 +81,6 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for log_level_name */ const char *log_level_name(enum log_level level UNNEEDED) { fprintf(stderr, "log_level_name called!\n"); abort(); } diff --git a/common/Makefile b/common/Makefile index d18494317..b48f993f2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -46,10 +46,10 @@ COMMON_SRC_NOGEN := \ common/initial_channel.c \ common/initial_commit_tx.c \ common/iso4217.c \ - common/json.c \ - common/json_helpers.c \ + common/json_param.c \ + common/json_parse.c \ + common/json_parse_simple.c \ common/json_stream.c \ - common/json_tok.c \ common/key_derive.c \ common/keyset.c \ common/lease_rates.c \ @@ -58,7 +58,6 @@ COMMON_SRC_NOGEN := \ common/node_id.c \ common/onion.c \ common/onionreply.c \ - common/param.c \ common/peer_billboard.c \ common/peer_failed.c \ common/peer_io.c \ diff --git a/common/bolt11_json.c b/common/bolt11_json.c index b2280c47d..dde88c6dd 100644 --- a/common/bolt11_json.c +++ b/common/bolt11_json.c @@ -6,7 +6,6 @@ #include #include #include -#include #include static void json_add_fallback(struct json_stream *response, diff --git a/common/json.c b/common/json.c deleted file mode 100644 index 08fa96e88..000000000 --- a/common/json.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* JSON core and helpers */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const char *json_tok_full(const char *buffer, const jsmntok_t *t) -{ - if (t->type == JSMN_STRING) - return buffer + t->start - 1; - return buffer + t->start; -} - -/* Include " if it's a string. */ -int json_tok_full_len(const jsmntok_t *t) -{ - if (t->type == JSMN_STRING) - return t->end - t->start + 2; - return t->end - t->start; -} - -bool json_tok_strneq(const char *buffer, const jsmntok_t *tok, - const char *str, size_t len) -{ - if (tok->type != JSMN_STRING) - return false; - return memeq(buffer + tok->start, tok->end - tok->start, str, len); -} - -bool json_tok_streq(const char *buffer, const jsmntok_t *tok, const char *str) -{ - return json_tok_strneq(buffer, tok, str, strlen(str)); -} - -bool json_tok_startswith(const char *buffer, const jsmntok_t *tok, - const char *prefix) -{ - if (tok->type != JSMN_STRING) - return false; - if (tok->end - tok->start < strlen(prefix)) - return false; - return memcmp(buffer + tok->start, - prefix, strlen(prefix)) == 0; -} - -bool json_tok_endswith(const char *buffer, const jsmntok_t *tok, - const char *suffix) -{ - if (tok->type != JSMN_STRING) - return false; - if (tok->end - tok->start < strlen(suffix)) - return false; - return memcmp(buffer + tok->end - strlen(suffix), - suffix, strlen(suffix)) == 0; -} - -char *json_strdup(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) -{ - return tal_strndup(ctx, buffer + tok->start, tok->end - tok->start); -} - -bool json_to_u64(const char *buffer, const jsmntok_t *tok, - uint64_t *num) -{ - char *end; - unsigned long long l; - - l = strtoull(buffer + tok->start, &end, 0); - if (end != buffer + tok->end) - return false; - - BUILD_ASSERT(sizeof(l) >= sizeof(*num)); - *num = l; - - /* Check for overflow */ - if (l == ULLONG_MAX && errno == ERANGE) - return false; - - if (*num != l) - return false; - - return true; -} - -bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num) -{ - char *end; - long long l; - - l = strtoll(buffer + tok->start, &end, 0); - if (end != buffer + tok->end) - return false; - - BUILD_ASSERT(sizeof(l) >= sizeof(*num)); - *num = l; - - /* Check for overflow/underflow */ - if ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) - return false; - - /* Check if the number did not fit in `s64` (in case `long long` - is a bigger type). */ - if (*num != l) - return false; - - return true; -} - -bool json_to_millionths(const char *buffer, const jsmntok_t *tok, - u64 *millionths) -{ - int decimal_places = -1; - bool has_digits = 0; - - *millionths = 0; - for (int i = tok->start; i < tok->end; i++) { - if (isdigit(buffer[i])) { - has_digits = true; - /* Ignore too much precision */ - if (decimal_places >= 0 && ++decimal_places > 6) - continue; - if (mul_overflows_u64(*millionths, 10)) - return false; - *millionths *= 10; - if (add_overflows_u64(*millionths, buffer[i] - '0')) - return false; - *millionths += buffer[i] - '0'; - } else if (buffer[i] == '.') { - if (decimal_places != -1) - return false; - decimal_places = 0; - } else - return false; - } - - if (!has_digits) - return false; - - if (decimal_places == -1) - decimal_places = 0; - - while (decimal_places < 6) { - if (mul_overflows_u64(*millionths, 10)) - return false; - *millionths *= 10; - decimal_places++; - } - return true; -} - -bool json_to_number(const char *buffer, const jsmntok_t *tok, - unsigned int *num) -{ - uint64_t u64; - - if (!json_to_u64(buffer, tok, &u64)) - return false; - *num = u64; - - /* Just in case it doesn't fit. */ - if (*num != u64) - return false; - return true; -} - -bool json_to_u16(const char *buffer, const jsmntok_t *tok, - short unsigned int *num) -{ - uint64_t u64; - - if (!json_to_u64(buffer, tok, &u64)) - return false; - *num = u64; - - /* Just in case it doesn't fit. */ - if (*num != u64) - return false; - return true; -} - -bool json_to_u32(const char *buffer, const jsmntok_t *tok, - uint32_t *num) -{ - uint64_t u64; - - if (!json_to_u64(buffer, tok, &u64)) - return false; - *num = u64; - - /* Just in case it doesn't fit. */ - if (*num != u64) - return false; - return true; -} - -bool json_to_int(const char *buffer, const jsmntok_t *tok, int *num) -{ - s64 tmp; - - if (!json_to_s64(buffer, tok, &tmp)) - return false; - *num = tmp; - - /* Just in case it doesn't fit. */ - if (*num != tmp) - return false; - - return true; -} - -bool json_to_errcode(const char *buffer, const jsmntok_t *tok, errcode_t *errcode) -{ - s64 tmp; - - if (!json_to_s64(buffer, tok, &tmp)) - return false; - *errcode = tmp; - - /* Just in case it doesn't fit. */ - if (*errcode != tmp) - return false; - - return true; -} - -bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b) -{ - if (tok->type != JSMN_PRIMITIVE) - return false; - 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; - } - return false; -} - -bool json_to_sha256(const char *buffer, const jsmntok_t *tok, struct sha256 *dest) -{ - if (tok->type != JSMN_STRING) - return false; - - return hex_decode(buffer + tok->start, tok->end - tok->start, dest, - sizeof(struct sha256)); -} - -u8 *json_tok_bin_from_hex(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) -{ - u8 *result; - size_t hexlen, rawlen; - hexlen = tok->end - tok->start; - rawlen = hex_data_size(hexlen); - - result = tal_arr(ctx, u8, rawlen); - if (!hex_decode(buffer + tok->start, hexlen, result, rawlen)) - return tal_free(result); - - return result; -} - -bool json_tok_is_num(const char *buffer, const jsmntok_t *tok) -{ - if (tok->type != JSMN_PRIMITIVE) - return false; - - for (int i = tok->start; i < tok->end; i++) - if (!cisdigit(buffer[i])) - return false; - return true; -} - -bool json_tok_is_null(const char *buffer, const jsmntok_t *tok) -{ - if (tok->type != JSMN_PRIMITIVE) - return false; - return buffer[tok->start] == 'n'; -} - -const jsmntok_t *json_next(const jsmntok_t *tok) -{ - const jsmntok_t *t; - size_t i; - - for (t = tok + 1, i = 0; i < tok->size; i++) - t = json_next(t); - - return t; -} - -static const jsmntok_t *json_get_membern(const char *buffer, - const jsmntok_t tok[], - const char *label, size_t len) -{ - const jsmntok_t *t; - size_t i; - - if (tok->type != JSMN_OBJECT) - return NULL; - - json_for_each_obj(i, t, tok) - if (json_tok_strneq(buffer, t, label, len)) - return t + 1; - - return NULL; -} - -const jsmntok_t *json_get_member(const char *buffer, const jsmntok_t tok[], - const char *label) -{ - return json_get_membern(buffer, tok, label, strlen(label)); -} - -const jsmntok_t *json_get_arr(const jsmntok_t tok[], size_t index) -{ - const jsmntok_t *t; - size_t i; - - if (tok->type != JSMN_ARRAY) - return NULL; - - json_for_each_arr(i, t, tok) { - if (index == 0) - return t; - index--; - } - - return NULL; -} - -/*----------------------------------------------------------------------------- -JSMN Result Validation Starts ------------------------------------------------------------------------------*/ -/*~ LIBJSMN is a fast, small JSON parsing library. - * - * "Fast, small" means it does not, in fact, do a - * lot of checking for invalid JSON. - * - * For example, by itself it would accept the strings - * `{"1" "2" "3" "4"}` and `["key": 1 2 3 4]` as valid. - * Obviously those are not in any way valid JSON. - * - * This part of the code performs some filtering so - * that at least some of the invalid JSON that - * LIBJSMN accepts, will be rejected by - * json_parse_input. It also checks that strings are valid UTF-8. - */ - -/*~ These functions are used in JSMN validation. - * - * The calling convention is that the "current" token - * is passed in as the first argument, and after the - * validator, is returned from the function. - * - * p = validate_jsmn_datum(p, end, valid); - * - * The reason has to do with typical C ABIs. - * Usually, the first few arguments are passed in via - * register, and the return value is also returned - * via register. - * This calling convention generally ensures that - * the current token pointer `p` is always in a - * register and is never forced into memory by the - * compiler. - * - * These functions are pre-declared here as they - * are interrecursive. - * Note that despite the recursion, `p` is only ever - * advanced, and there is only ever one `p` value, - * thus the overall algorithm is strict O(n) - * (*not* amortized) in time. - * The recursion does mean the algorithm is O(d) - * in memory (specifically stack frames), where d - * is the nestedness of objects in the input. - * This may become an issue later if we are in a - * stack-limited environment, such as if we actually - * went and used threads. - */ -/* Validate a *single* datum. */ -static const jsmntok_t * -validate_jsmn_datum(const char *buf, - const jsmntok_t *p, - const jsmntok_t *end, - bool *valid); -/*~ Validate a key-value pair. - * - * In JSMN, objects are not dictionaries. - * Instead, they are a sequence of datums. - * - * In fact, objects and arrays in JSMN are "the same", - * they only differ in delimiter characters. - * - * Of course, in "real" JSON, an object is a dictionary - * of key-value pairs. - * - * So what JSMN does is that the syntax "key": "value" - * is considered a *single* datum, a string "key" - * that contains a value "value". - * - * Indeed, JSMN accepts `["key": "value"]` as well as - * `{"item1", "item2"}`. - * The entire point of the validate_jsmn_result function - * is to reject such improper arrays and objects. - */ -static const jsmntok_t * -validate_jsmn_keyvalue(const char *buf, - const jsmntok_t *p, - const jsmntok_t *end, - bool *valid); - -static const jsmntok_t * -validate_jsmn_datum(const char *buf, - const jsmntok_t *p, - const jsmntok_t *end, - bool *valid) -{ - int i; - int sz; - - if (p >= end) { - *valid = false; - return p; - } - - switch (p->type) { - case JSMN_STRING: - if (!utf8_check(buf + p->start, p->end - p->start)) - *valid = false; - /* Fall thru */ - case JSMN_UNDEFINED: - case JSMN_PRIMITIVE: - /* These types should not have sub-datums. */ - if (p->size != 0) - *valid = false; - else - ++p; - break; - - case JSMN_ARRAY: - /* Save the array size; we will advance p. */ - sz = p->size; - ++p; - for (i = 0; i < sz; ++i) { - /* Arrays should only contain standard JSON datums. */ - p = validate_jsmn_datum(buf, p, end, valid); - if (!*valid) - break; - } - break; - - case JSMN_OBJECT: - /* Save the object size; we will advance p. */ - sz = p->size; - ++p; - for (i = 0; i < sz; ++i) { - /* Objects should only contain key-value pairs. */ - p = validate_jsmn_keyvalue(buf, p, end, valid); - if (!*valid) - break; - } - break; - - default: - *valid = false; - break; - } - - return p; -} -/* Key-value pairs *must* be strings with size 1. */ -static inline const jsmntok_t * -validate_jsmn_keyvalue(const char *buf, - const jsmntok_t *p, - const jsmntok_t *end, - bool *valid) -{ - if (p >= end) { - *valid = false; - return p; - } - - /* Check key. - * - * JSMN parses the syntax `"key": "value"` as a - * JSMN_STRING of size 1, containing the value - * datum as a sub-datum. - * - * Thus, keys in JSON objects are really strings - * that "contain" the value, thus we check if - * the size is 1. - * - * JSMN supports a non-standard syntax such as - * `"key": 1 2 3 4`, which it considers as a - * string object that contains a sequence of - * sub-datums 1 2 3 4. - * The check below that p->size == 1 also - * incidentally rejects that non-standard - * JSON. - */ - if (p->type != JSMN_STRING || p->size != 1 - || !utf8_check(buf + p->start, p->end - p->start)) { - *valid = false; - return p; - } - - ++p; - return validate_jsmn_datum(buf, p, end, valid); -} - -/** validate_jsmn_parse_output - * - * @brief Validates the result of jsmn_parse. - * - * @desc LIBJMSN is a small fast library, not a - * comprehensive library. - * - * This simply means that LIBJSMN will accept a - * *lot* of very strange text that is technically - * not JSON. - * - * For example, LIBJSMN would accept the strings - * `{"1" "2" "3" "4"}` and `["key": 1 2 3 4]` as valid. - * - * This can lead to strange sequences of jsmntok_t - * objects. - * Unfortunately, most of our code assumes that - * the data fed into our JSON-RPC interface is - * valid JSON, and in particular is not invalid - * JSON that tickles LIBJSMN into emitting - * strange sequences of `jsmntok_t`. - * - * This function detects such possible problems - * and returns false if such an issue is found. - * If so, it is probably unsafe to pass the - * `jsmntok_t` generated by LIBJSMN to any other - * parts of our code. - * - * @param p - The first jsmntok_t token to process. - * This function does not assume that semantically - * only one JSON datum is processed; it does expect - * a sequence of complete JSON datums (which is - * what LIBJSMN *should* output). - * @param end - One past the end of jsmntok_t. - * Basically, this function is assured to read tokens - * starting at p up to end - 1. - * If p >= end, this will not validate anything and - * trivially return true. - * - * @return true if there appears to be no problem - * with the jsmntok_t sequence outputted by - * `jsmn_parse`, false otherwise. - */ -static bool -validate_jsmn_parse_output(const char *buf, - const jsmntok_t *p, const jsmntok_t *end) -{ - bool valid = true; - - while (p < end && valid) - p = validate_jsmn_datum(buf, p, end, &valid); - - return valid; -} - -/*----------------------------------------------------------------------------- -JSMN Result Validation Ends ------------------------------------------------------------------------------*/ - -void toks_reset(jsmntok_t *toks) -{ - assert(tal_count(toks) >= 1); - toks[0].type = JSMN_UNDEFINED; -} - -jsmntok_t *toks_alloc(const tal_t *ctx) -{ - jsmntok_t *toks = tal_arr(ctx, jsmntok_t, 10); - toks_reset(toks); - return toks; -} - -bool json_parse_input(jsmn_parser *parser, - jsmntok_t **toks, - const char *input, int len, - bool *complete) -{ - int ret; - -again: - ret = jsmn_parse(parser, input, len, *toks, tal_count(*toks) - 1); - - switch (ret) { - case JSMN_ERROR_INVAL: - return false; - case JSMN_ERROR_NOMEM: - tal_resize(toks, tal_count(*toks) * 2); - goto again; - } - - /* Check whether we read at least one full root element, i.e., root - * element has its end set. */ - if ((*toks)[0].type == JSMN_UNDEFINED || (*toks)[0].end == -1) { - *complete = false; - return true; - } - - /* If we read a partial element at the end of the stream we'll get a - * ret=JSMN_ERROR_PART, but due to the previous check we know we read at - * least one full element, so count tokens that are part of this root - * element. */ - ret = json_next(*toks) - *toks; - - if (!validate_jsmn_parse_output(input, *toks, *toks + ret)) - return false; - - /* Cut to length and return. */ - tal_resize(toks, ret + 1); - /* Make sure last one is always referenceable. */ - (*toks)[ret].type = -1; - (*toks)[ret].start = (*toks)[ret].end = (*toks)[ret].size = 0; - - *complete = true; - return true; -} - -jsmntok_t *json_parse_simple(const tal_t *ctx, const char *input, int len) -{ - bool complete; - jsmn_parser parser; - jsmntok_t *toks = toks_alloc(ctx); - - jsmn_init(&parser); - - if (!json_parse_input(&parser, &toks, input, len, &complete) - || !complete) - return tal_free(toks); - return toks; -} - -const char *jsmntype_to_string(jsmntype_t t) -{ - switch (t) { - case JSMN_UNDEFINED : - return "UNDEFINED"; - case JSMN_OBJECT : - return "OBJECT"; - case JSMN_ARRAY : - return "ARRAY"; - case JSMN_STRING : - return "STRING"; - case JSMN_PRIMITIVE : - return "PRIMITIVE"; - } - return "INVALID"; -} - -jsmntok_t *json_tok_copy(const tal_t *ctx, const jsmntok_t *tok) -{ - return tal_dup_arr(ctx, jsmntok_t, tok, json_next(tok) - tok, 0); -} - -void json_tok_remove(jsmntok_t **tokens, - jsmntok_t *obj_or_array, const jsmntok_t *tok, size_t num) -{ - const jsmntok_t *src = tok; - const jsmntok_t *end = json_next(*tokens); - jsmntok_t *dest = *tokens + (tok - *tokens); - int remove_count; - - assert(*tokens); - assert(obj_or_array->type == JSMN_ARRAY - || obj_or_array->type == JSMN_OBJECT); - /* obj_or_array must be inside tokens, and tok must be inside - * obj_or_array */ - assert(obj_or_array >= *tokens - && obj_or_array < *tokens + tal_count(*tokens)); - assert(tok >= obj_or_array - && tok < *tokens + tal_count(*tokens)); - - for (int i = 0; i < num; i++) - src = json_next(src); - - /* Don't give us a num which goes over end of obj_or_array. */ - assert(src <= json_next(obj_or_array)); - - remove_count = src - tok; - - memmove(dest, src, sizeof(jsmntok_t) * (end - src)); - - /* Subtract first: this ptr may move after tal_resize! */ - obj_or_array->size -= num; - tal_resize(tokens, tal_count(*tokens) - remove_count); -} - -/* talfmt take a ctx pointer and return NULL or a valid pointer. - * fmt takes the argument, and returns a bool. - * - * This function returns NULL on success, or errmsg on failure. -*/ -static const char *handle_percent(const char *buffer, - const jsmntok_t *tok, - va_list *ap) -{ - void *ctx; - const char *fmtname; - - /* This is set to (dummy) json_scan if it's a non-tal fmt */ - ctx = va_arg(*ap, void *); - fmtname = va_arg(*ap, const char *); - if (ctx != json_scan) { - void *(*talfmt)(void *, const char *, const jsmntok_t *); - void **p; - p = va_arg(*ap, void **); - talfmt = va_arg(*ap, void *(*)(void *, const char *, const jsmntok_t *)); - *p = talfmt(ctx, buffer, tok); - if (*p != NULL) - return NULL; - } else { - bool (*fmt)(const char *, const jsmntok_t *, void *); - void *p; - - p = va_arg(*ap, void *); - fmt = va_arg(*ap, bool (*)(const char *, const jsmntok_t *, void *)); - if (fmt(buffer, tok, p)) - return NULL; - } - - return tal_fmt(tmpctx, "%s could not parse %.*s", - fmtname, - json_tok_full_len(tok), - json_tok_full(buffer, tok)); -} - -/* GUIDE := OBJ | ARRAY | '%' - * OBJ := '{' FIELDLIST '}' - * FIELDLIST := FIELD [',' FIELD]* - * FIELD := LITERAL ':' FIELDVAL - * FIELDVAL := OBJ | ARRAY | LITERAL | '%' - * ARRAY := '[' ARRLIST ']' - * ARRLIST := ARRELEM [',' ARRELEM]* - * ARRELEM := NUMBER ':' FIELDVAL - */ - -static void parse_literal(const char **guide, - const char **literal, - size_t *len) -{ - *literal = *guide; - *len = strspn(*guide, - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "_-"); - *guide += *len; -} - -static void parse_number(const char **guide, u32 *number) -{ - char *endp; - long int l; - - l = strtol(*guide, &endp, 10); - assert(endp != *guide); - assert(errno != ERANGE); - - /* Test for overflow */ - *number = l; - assert(*number == l); - - *guide = endp; -} - -static char guide_consume_one(const char **guide) -{ - char c = **guide; - (*guide)++; - return c; -} - -static void guide_must_be(const char **guide, char c) -{ - char actual = guide_consume_one(guide); - assert(actual == c); -} - -/* Recursion: return NULL on success, errmsg on fail */ -static const char *parse_obj(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap); - -static const char *parse_arr(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap); - -static const char *parse_guide(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const char *errmsg; - - if (**guide == '{') { - errmsg = parse_obj(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - } else if (**guide == '[') { - errmsg = parse_arr(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - } else { - guide_must_be(guide, '%'); - errmsg = handle_percent(buffer, tok, ap); - if (errmsg) - return errmsg; - } - return NULL; -} - -static const char *parse_fieldval(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const char *errmsg; - - if (**guide == '{') { - errmsg = parse_obj(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - } else if (**guide == '[') { - errmsg = parse_arr(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - } else if (**guide == '%') { - guide_consume_one(guide); - errmsg = handle_percent(buffer, tok, ap); - if (errmsg) - return errmsg; - } else { - const char *literal; - size_t len; - - /* Literal must match exactly (modulo quotes for strings) */ - parse_literal(guide, &literal, &len); - if (!memeq(buffer + tok->start, tok->end - tok->start, - literal, len)) { - return tal_fmt(tmpctx, - "%.*s does not match expected %.*s", - json_tok_full_len(tok), - json_tok_full(buffer, tok), - (int)len, literal); - } - } - return NULL; -} - -static const char *parse_field(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const jsmntok_t *member; - size_t len; - const char *memname; - - parse_literal(guide, &memname, &len); - guide_must_be(guide, ':'); - - member = json_get_membern(buffer, tok, memname, len); - if (!member) { - return tal_fmt(tmpctx, "object does not have member %.*s", - (int)len, memname); - } - - return parse_fieldval(buffer, member, guide, ap); -} - -static const char *parse_fieldlist(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - for (;;) { - const char *errmsg; - - errmsg = parse_field(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - if (**guide != ',') - break; - guide_consume_one(guide); - } - return NULL; -} - -static const char *parse_obj(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const char *errmsg; - - guide_must_be(guide, '{'); - - if (tok->type != JSMN_OBJECT) { - return tal_fmt(tmpctx, "token is not an object: %.*s", - json_tok_full_len(tok), - json_tok_full(buffer, tok)); - } - - errmsg = parse_fieldlist(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - - guide_must_be(guide, '}'); - return NULL; -} - -static const char *parse_arrelem(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const jsmntok_t *member; - u32 idx; - - parse_number(guide, &idx); - guide_must_be(guide, ':'); - - member = json_get_arr(tok, idx); - if (!member) { - return tal_fmt(tmpctx, "token has no index %u: %.*s", - idx, - json_tok_full_len(tok), - json_tok_full(buffer, tok)); - } - - return parse_fieldval(buffer, member, guide, ap); -} - -static const char *parse_arrlist(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const char *errmsg; - - for (;;) { - errmsg = parse_arrelem(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - if (**guide != ',') - break; - guide_consume_one(guide); - } - return NULL; -} - -static const char *parse_arr(const char *buffer, - const jsmntok_t *tok, - const char **guide, - va_list *ap) -{ - const char *errmsg; - - guide_must_be(guide, '['); - - if (tok->type != JSMN_ARRAY) { - return tal_fmt(tmpctx, "token is not an array: %.*s", - json_tok_full_len(tok), - json_tok_full(buffer, tok)); - } - - errmsg = parse_arrlist(buffer, tok, guide, ap); - if (errmsg) - return errmsg; - - guide_must_be(guide, ']'); - return NULL; -} - -const char *json_scanv(const tal_t *ctx, - const char *buffer, - const jsmntok_t *tok, - const char *guide, - va_list ap) -{ - va_list cpy; - const char *orig_guide = guide, *errmsg; - - /* We need this, since &ap doesn't work on some platforms... */ - va_copy(cpy, ap); - errmsg = parse_guide(buffer, tok, &guide, &cpy); - va_end(cpy); - - if (errmsg) { - return tal_fmt(ctx, "Parsing '%.*s': %s", - (int)(guide - orig_guide), orig_guide, - errmsg); - } - assert(guide[0] == '\0'); - return NULL; -} - -const char *json_scan(const tal_t *ctx, - const char *buffer, - const jsmntok_t *tok, - const char *guide, - ...) -{ - va_list ap; - const char *ret; - - va_start(ap, guide); - ret = json_scanv(ctx, buffer, tok, guide, ap); - va_end(ap); - return ret; -} - -void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value) -{ - json_add_member(result, fieldname, false, "%u", value); -} - -void json_add_u64(struct json_stream *result, const char *fieldname, - uint64_t value) -{ - json_add_member(result, fieldname, false, "%"PRIu64, value); -} - -void json_add_s64(struct json_stream *result, const char *fieldname, - int64_t value) -{ - json_add_member(result, fieldname, false, "%"PRIi64, value); -} - -void json_add_u32(struct json_stream *result, const char *fieldname, - uint32_t value) -{ - json_add_member(result, fieldname, false, "%u", value); -} - -void json_add_s32(struct json_stream *result, const char *fieldname, - int32_t value) -{ - json_add_member(result, fieldname, false, "%d", value); -} - -void json_add_literal(struct json_stream *result, const char *fieldname, - const char *literal, int len) -{ - /* Literal may contain quotes, so bypass normal checks */ - char *dest = json_member_direct(result, fieldname, len); - memcpy(dest, literal, len); -} - -void json_add_stringn(struct json_stream *result, const char *fieldname, - const char *value TAKES, size_t value_len) -{ - json_add_member(result, fieldname, true, "%.*s", (int)value_len, value); - if (taken(value)) - tal_free(value); -} - -void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES) -{ - json_add_stringn(result, fieldname, value, strlen(value)); -} - -void json_add_bool(struct json_stream *result, const char *fieldname, bool value) -{ - json_add_member(result, fieldname, false, value ? "true" : "false"); -} - -void json_add_null(struct json_stream *stream, const char *fieldname) -{ - json_add_member(stream, fieldname, false, "null"); -} - -void json_add_hex(struct json_stream *js, const char *fieldname, - const void *data, size_t len) -{ - /* Size without NUL term */ - size_t hexlen = hex_str_size(len) - 1; - char *dest; - - dest = json_member_direct(js, fieldname, 1 + hexlen + 1); - dest[0] = '"'; - if (!hex_encode(data, len, dest + 1, hexlen + 1)) - abort(); - dest[1+hexlen] = '"'; -} - -void json_add_hex_talarr(struct json_stream *result, - const char *fieldname, - const tal_t *data) -{ - json_add_hex(result, fieldname, data, tal_bytelen(data)); -} - -void json_add_escaped_string(struct json_stream *result, const char *fieldname, - const struct json_escape *esc TAKES) -{ - /* Already escaped, don't re-escape! */ - char *dest = json_member_direct(result, fieldname, - 1 + strlen(esc->s) + 1); - - dest[0] = '"'; - memcpy(dest + 1, esc->s, strlen(esc->s)); - dest[1+strlen(esc->s)] = '"'; - if (taken(esc)) - tal_free(esc); -} - -void json_add_timeabs(struct json_stream *result, const char *fieldname, - struct timeabs t) -{ - json_add_member(result, fieldname, false, "%" PRIu64 ".%03" PRIu64, - (u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000); -} - -void json_add_time(struct json_stream *result, const char *fieldname, - struct timespec ts) -{ - char timebuf[100]; - - snprintf(timebuf, sizeof(timebuf), "%lu.%09u", - (unsigned long)ts.tv_sec, - (unsigned)ts.tv_nsec); - json_add_string(result, fieldname, timebuf); -} - -void json_add_timeiso(struct json_stream *result, - const char *fieldname, - struct timeabs *time) -{ - char iso8601_msec_fmt[sizeof("YYYY-mm-ddTHH:MM:SS.%03dZ")]; - char iso8601_s[sizeof("YYYY-mm-ddTHH:MM:SS.nnnZ")]; - - strftime(iso8601_msec_fmt, sizeof(iso8601_msec_fmt), - "%FT%T.%%03dZ", gmtime(&time->ts.tv_sec)); - snprintf(iso8601_s, sizeof(iso8601_s), - iso8601_msec_fmt, (int) time->ts.tv_nsec / 1000000); - - json_add_string(result, fieldname, iso8601_s); -} - - -void json_add_tok(struct json_stream *result, const char *fieldname, - const jsmntok_t *tok, const char *buffer) -{ - char *space; - assert(tok->type != JSMN_UNDEFINED); - - space = json_member_direct(result, fieldname, json_tok_full_len(tok)); - memcpy(space, json_tok_full(buffer, tok), json_tok_full_len(tok)); -} - -void json_add_errcode(struct json_stream *result, const char *fieldname, - errcode_t code) -{ - json_add_member(result, fieldname, false, "%"PRIerrcode, code); -} - -void json_add_invstring(struct json_stream *result, const char *invstring) -{ - if (strstarts(invstring, "lni")) - json_add_string(result, "bolt12", invstring); - else - json_add_string(result, "bolt11", invstring); -} diff --git a/common/json.h b/common/json.h deleted file mode 100644 index bdd867f5b..000000000 --- a/common/json.h +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef LIGHTNING_COMMON_JSON_H -#define LIGHTNING_COMMON_JSON_H -#include "config.h" -#include -#include -#include - -#define JSMN_STRICT 1 -# include - -struct json_escape; -struct json_stream; -struct timeabs; -struct timespec; - -/* Include " if it's a string. */ -const char *json_tok_full(const char *buffer, const jsmntok_t *t); - -/* Include " if it's a string. */ -int json_tok_full_len(const jsmntok_t *t); - -/* Is this a string equal to str? */ -bool json_tok_streq(const char *buffer, const jsmntok_t *tok, const char *str); - -/* Is this a string equal to str of length len? */ -bool json_tok_strneq(const char *buffer, const jsmntok_t *tok, - const char *str, size_t len); - -/* Does this string token start with prefix? */ -bool json_tok_startswith(const char *buffer, const jsmntok_t *tok, - const char *prefix); - -/* Does this string token end with suffix? */ -bool json_tok_endswith(const char *buffer, const jsmntok_t *tok, - const char *suffix); - -/* Allocate a tal string copy */ -char *json_strdup(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); - -/* Decode a hex-encoded binary */ -u8 *json_tok_bin_from_hex(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); - -/* Extract number from this (may be a string, or a number literal) */ -bool json_to_number(const char *buffer, const jsmntok_t *tok, - unsigned int *num); - -/* Extract number from this (may be a string, or a number literal) */ -bool json_to_u64(const char *buffer, const jsmntok_t *tok, - uint64_t *num); - -/* Extract signed 64 bit integer from this (may be a string, or a number literal) */ -bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num); - -/* Extract number from this (may be a string, or a number literal) */ -bool json_to_u32(const char *buffer, const jsmntok_t *tok, - uint32_t *num); - -/* Extract number from this (may be a string, or a number literal) */ -bool json_to_u16(const char *buffer, const jsmntok_t *tok, - uint16_t *num); - -bool json_to_sha256(const char *buffer, const jsmntok_t *tok, struct sha256 *dest); -/* - * Extract a non-negative (either 0 or positive) floating-point number from this - * (must be a number literal), multiply it by 1 million and return it as an - * integer. Any fraction smaller than 0.000001 is ignored. - */ -bool json_to_millionths(const char *buffer, const jsmntok_t *tok, - u64 *millionths); - -/* Extract signed integer from this (may be a string, or a number literal) */ -bool json_to_int(const char *buffer, const jsmntok_t *tok, int *num); - -/* Extract an error code from this (may be a string, or a number literal) */ -bool json_to_errcode(const char *buffer, const jsmntok_t *tok, errcode_t *errcode); - -/* Extract boolean from this */ -bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b); - -/* Is this a number? [0..9]+ */ -bool json_tok_is_num(const char *buffer, const jsmntok_t *tok); - -/* Is this the null primitive? */ -bool json_tok_is_null(const char *buffer, const jsmntok_t *tok); - -/* Returns next token with same parent (WARNING: slow!). */ -const jsmntok_t *json_next(const jsmntok_t *tok); - -/* Get top-level member. */ -const jsmntok_t *json_get_member(const char *buffer, const jsmntok_t tok[], - const char *label); - -/* Get index'th array member. */ -const jsmntok_t *json_get_arr(const jsmntok_t tok[], size_t index); - -/* Allocate a starter array of tokens for json_parse_input */ -jsmntok_t *toks_alloc(const tal_t *ctx); - -/* Reset a token array to reuse it. */ -void toks_reset(jsmntok_t *toks); - -/** - * json_parse_input: parse and validate JSON. - * @parser: parser initialized with jsmn_init. - * @toks: tallocated array from toks_alloc() - * @input, @len: input string. - * @complete: set to true if the valid JSON is complete, or NULL if must be. - * - * This returns false if the JSON is invalid, true otherwise. - * If it returns true, *@complete indicates that (*@toks)[0] points to a - * valid, complete JSON element. If @complete is NULL, then incomplete - * JSON returns false (i.e. is considered invalid). - * - * *@toks is resized to the complete set of tokens, with a dummy - * terminator (type == -1) at the end. - * - * If it returns true, and *@complete is false, you can append more - * data to @input and call it again (with the same perser) and the parser - * will continue where it left off. -*/ -bool json_parse_input(jsmn_parser *parser, - jsmntok_t **toks, - const char *input, int len, - bool *complete); - -/* Simplified version of above which parses only a complete, valid - * JSON string */ -jsmntok_t *json_parse_simple(const tal_t *ctx, const char *input, int len); - -/* Convert a jsmntype_t enum to a human readable string. */ -const char *jsmntype_to_string(jsmntype_t t); - -/* Return a copy of a json value as an array. */ -jsmntok_t *json_tok_copy(const tal_t *ctx, const jsmntok_t *tok); - -/* - * Remove @num json values from a json array or object @obj. @tok points - * to the first value to remove. The array @tokens will be resized. - */ -void json_tok_remove(jsmntok_t **tokens, - jsmntok_t *obj_or_array, const jsmntok_t *tok, size_t num); - -/* Guide is % for a token: each must be followed by JSON_SCAN(). - * Returns NULL on error (asserts() on bad guide). */ -const char *json_scan(const tal_t *ctx, - const char *buffer, - const jsmntok_t *tok, - const char *guide, - ...); - -/* eg. JSON_SCAN(json_to_bool, &boolvar) */ -#define JSON_SCAN(fmt, var) \ - json_scan, \ - stringify(fmt), \ - ((var) + 0*sizeof(fmt((const char *)NULL, \ - (const jsmntok_t *)NULL, var) == true)), \ - (fmt) - -/* eg. JSON_SCAN_TAL(tmpctx, json_strdup, &charvar) */ -#define JSON_SCAN_TAL(ctx, fmt, var) \ - (ctx), \ - stringify(fmt), \ - ((var) + 0*sizeof((*var) = fmt((ctx), \ - (const char *)NULL, \ - (const jsmntok_t *)NULL))), \ - (fmt) - -/* Already-have-varargs version */ -const char *json_scanv(const tal_t *ctx, - const char *buffer, - const jsmntok_t *tok, - const char *guide, - va_list ap); - -/* Iterator macro for array: i is counter, t is token ptr, arr is JSMN_ARRAY */ -#define json_for_each_arr(i, t, arr) \ - for (i = 0, t = (arr) + 1; i < (arr)->size; t = json_next(t), i++) - -/* Iterator macro for object: i is counter, t is token ptr (t+1 is - * contents of obj member), obj is JSMN_OBJECT */ -#define json_for_each_obj(i, t, obj) \ - for (i = 0, t = (obj) + 1; i < (obj)->size; t = json_next(t+1), i++) - - -/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. Turns - * any non-printable chars into JSON escapes, but leaves existing escapes alone. - */ -void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES); - -/* '"fieldname" : "value[:value_len]"' or '"value[:value_len]"' if - * fieldname is NULL. Turns any non-printable chars into JSON - * escapes, but leaves existing escapes alone. - */ -void json_add_stringn(struct json_stream *result, const char *fieldname, - const char *value TAKES, size_t value_len); - -/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. String must - * already be JSON escaped as necessary. */ -void json_add_escaped_string(struct json_stream *result, - const char *fieldname, - const struct json_escape *esc TAKES); - -/* '"fieldname" : literal' or 'literal' if fieldname is NULL*/ -void json_add_literal(struct json_stream *result, const char *fieldname, - const char *literal, int len); -/* '"fieldname" : value' or 'value' if fieldname is NULL */ -void json_add_num(struct json_stream *result, const char *fieldname, - unsigned int value); -/* '"fieldname" : value' or 'value' if fieldname is NULL */ -void json_add_u64(struct json_stream *result, const char *fieldname, - uint64_t value); -/* '"fieldname" : value' or 'value' if fieldname is NULL */ -void json_add_s64(struct json_stream *result, const char *fieldname, - int64_t value); -/* '"fieldname" : value' or 'value' if fieldname is NULL */ -void json_add_u32(struct json_stream *result, const char *fieldname, - uint32_t value); -/* '"fieldname" : value' or 'value' if fieldname is NULL */ -void json_add_s32(struct json_stream *result, const char *fieldname, - int32_t value); -/* '"fieldname" : true|false' or 'true|false' if fieldname is NULL */ -void json_add_bool(struct json_stream *result, const char *fieldname, - bool value); - -/* '"fieldname" : null' or 'null' if fieldname is NULL */ -void json_add_null(struct json_stream *stream, const char *fieldname); - -/* '"fieldname" : "0189abcdef..."' or "0189abcdef..." if fieldname is NULL */ -void json_add_hex(struct json_stream *result, const char *fieldname, - const void *data, size_t len); -/* '"fieldname" : "0189abcdef..."' or "0189abcdef..." if fieldname is NULL */ -void json_add_hex_talarr(struct json_stream *result, - const char *fieldname, - const tal_t *data); - -void json_add_timeabs(struct json_stream *result, const char *fieldname, - struct timeabs t); - -/* used in log.c and notification.c*/ -void json_add_time(struct json_stream *result, const char *fieldname, - struct timespec ts); - -/* Add ISO_8601 timestamp string, i.e. "2019-09-07T15:50+01:00" */ -void json_add_timeiso(struct json_stream *result, - const char *fieldname, - struct timeabs *time); - -/* Add any json token */ -void json_add_tok(struct json_stream *result, const char *fieldname, - const jsmntok_t *tok, const char *buffer); - -/* Add an error code */ -void json_add_errcode(struct json_stream *result, const char *fieldname, - errcode_t code); - -/* Add "bolt11" or "bolt12" field, depending on invstring. */ -void json_add_invstring(struct json_stream *result, const char *invstring); - -#endif /* LIGHTNING_COMMON_JSON_H */ diff --git a/common/json_command.h b/common/json_command.h index 5c44f1c8e..88cf14aeb 100644 --- a/common/json_command.h +++ b/common/json_command.h @@ -4,7 +4,7 @@ #define LIGHTNING_COMMON_JSON_COMMAND_H #include "config.h" #include -#include +#include #include struct command; diff --git a/common/json_helpers.c b/common/json_helpers.c deleted file mode 100644 index 569b2c107..000000000 --- a/common/json_helpers.c +++ /dev/null @@ -1,495 +0,0 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -bool json_to_bitcoin_amount(const char *buffer, const jsmntok_t *tok, - uint64_t *satoshi) -{ - char *end; - unsigned long btc, sat; - - btc = strtoul(buffer + tok->start, &end, 10); - if (btc == ULONG_MAX && errno == ERANGE) - return false; - if (end != buffer + tok->end) { - /* Expect always 8 decimal places. */ - if (*end != '.' || buffer + tok->end - end != 9) - return false; - sat = strtoul(end+1, &end, 10); - if (sat == ULONG_MAX && errno == ERANGE) - return false; - if (end != buffer + tok->end) - return false; - } else - sat = 0; - - *satoshi = btc * (uint64_t)100000000 + sat; - if (*satoshi != btc * (uint64_t)100000000 + sat) - return false; - - return true; -} - -bool json_to_node_id(const char *buffer, const jsmntok_t *tok, - struct node_id *id) -{ - return node_id_from_hexstr(buffer + tok->start, - tok->end - tok->start, id); -} - -bool json_to_pubkey(const char *buffer, const jsmntok_t *tok, - struct pubkey *pubkey) -{ - return pubkey_from_hexstr(buffer + tok->start, - tok->end - tok->start, pubkey); -} - -bool json_to_msat(const char *buffer, const jsmntok_t *tok, - struct amount_msat *msat) -{ - return parse_amount_msat(msat, - buffer + tok->start, tok->end - tok->start); -} - -bool json_to_sat(const char *buffer, const jsmntok_t *tok, - struct amount_sat *sat) -{ - return parse_amount_sat(sat, buffer + tok->start, tok->end - tok->start); -} - -bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok, - struct amount_sat *sat) -{ - if (json_tok_streq(buffer, tok, "all")) { - *sat = AMOUNT_SAT(-1ULL); - return true; - } - return json_to_sat(buffer, tok, sat); -} - -bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok, - struct short_channel_id *scid) -{ - return (short_channel_id_from_str(buffer + tok->start, - tok->end - tok->start, scid)); -} - -bool json_to_txid(const char *buffer, const jsmntok_t *tok, - struct bitcoin_txid *txid) -{ - return bitcoin_txid_from_hex(buffer + tok->start, - tok->end - tok->start, txid); -} - -bool json_to_outpoint(const char *buffer, const jsmntok_t *tok, - struct bitcoin_outpoint *op) -{ - jsmntok_t t1, t2; - - if (!split_tok(buffer, tok, ':', &t1, &t2)) - return false; - - return json_to_txid(buffer, &t1, &op->txid) - && json_to_u32(buffer, &t2, &op->n); -} - -bool json_to_channel_id(const char *buffer, const jsmntok_t *tok, - struct channel_id *cid) -{ - return hex_decode(buffer + tok->start, tok->end - tok->start, - cid, sizeof(*cid)); -} - - -bool json_to_coin_mvt_tag(const char *buffer, const jsmntok_t *tok, - enum mvt_tag *tag) -{ - enum mvt_tag i_tag; - for (size_t i = 0; i < NUM_MVT_TAGS; i++) { - i_tag = (enum mvt_tag) i; - if (json_tok_streq(buffer, tok, mvt_tag_str(i_tag))) { - *tag = i_tag; - return true; - } - } - - return false; -} - -bool split_tok(const char *buffer, const jsmntok_t *tok, - char split, - jsmntok_t *a, - jsmntok_t *b) -{ - const char *p = memchr(buffer + tok->start, split, tok->end - tok->start); - if (!p) - return false; - - *a = *b = *tok; - a->end = p - buffer; - b->start = p + 1 - buffer; - - return true; -} - -bool json_to_secret(const char *buffer, const jsmntok_t *tok, struct secret *dest) -{ - return hex_decode(buffer + tok->start, tok->end - tok->start, - dest->data, sizeof(struct secret)); -} - -bool json_to_preimage(const char *buffer, const jsmntok_t *tok, struct preimage *preimage) -{ - size_t hexlen = tok->end - tok->start; - return hex_decode(buffer + tok->start, hexlen, preimage->r, sizeof(preimage->r)); -} - -struct wally_psbt *json_to_psbt(const tal_t *ctx, const char *buffer, - const jsmntok_t *tok) -{ - return psbt_from_b64(ctx, buffer + tok->start, tok->end - tok->start); -} - -struct tlv_obs2_onionmsg_payload_reply_path * -json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) -{ - struct tlv_obs2_onionmsg_payload_reply_path *rpath; - const jsmntok_t *hops, *t; - size_t i; - const char *err; - - rpath = tal(ctx, struct tlv_obs2_onionmsg_payload_reply_path); - err = json_scan(tmpctx, buffer, tok, "{blinding:%,first_node_id:%}", - JSON_SCAN(json_to_pubkey, &rpath->blinding), - JSON_SCAN(json_to_pubkey, &rpath->first_node_id), - NULL); - if (err) - return tal_free(rpath); - - hops = json_get_member(buffer, tok, "hops"); - if (!hops || hops->size < 1) - return tal_free(rpath); - - rpath->path = tal_arr(rpath, struct onionmsg_path *, hops->size); - json_for_each_arr(i, t, hops) { - rpath->path[i] = tal(rpath->path, struct onionmsg_path); - err = json_scan(tmpctx, buffer, t, "{id:%,encrypted_recipient_data:%}", - JSON_SCAN(json_to_pubkey, - &rpath->path[i]->node_id), - JSON_SCAN_TAL(rpath->path[i], - json_tok_bin_from_hex, - &rpath->path[i]->encrypted_recipient_data)); - if (err) - return tal_free(rpath); - } - - return rpath; -} - -struct tlv_onionmsg_payload_reply_path * -json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) -{ - struct tlv_onionmsg_payload_reply_path *rpath; - const jsmntok_t *hops, *t; - size_t i; - const char *err; - - rpath = tal(ctx, struct tlv_onionmsg_payload_reply_path); - err = json_scan(tmpctx, buffer, tok, "{blinding:%,first_node_id:%}", - JSON_SCAN(json_to_pubkey, &rpath->blinding), - JSON_SCAN(json_to_pubkey, &rpath->first_node_id), - NULL); - if (err) - return tal_free(rpath); - - hops = json_get_member(buffer, tok, "hops"); - if (!hops || hops->size < 1) - return tal_free(rpath); - - rpath->path = tal_arr(rpath, struct onionmsg_path *, hops->size); - json_for_each_arr(i, t, hops) { - rpath->path[i] = tal(rpath->path, struct onionmsg_path); - err = json_scan(tmpctx, buffer, t, "{id:%,encrypted_recipient_data:%}", - JSON_SCAN(json_to_pubkey, - &rpath->path[i]->node_id), - JSON_SCAN_TAL(rpath->path[i], - json_tok_bin_from_hex, - &rpath->path[i]->encrypted_recipient_data)); - if (err) - return tal_free(rpath); - } - - return rpath; -} - -void json_add_node_id(struct json_stream *response, - const char *fieldname, - const struct node_id *id) -{ - json_add_hex(response, fieldname, id->k, sizeof(id->k)); -} - -void json_add_channel_id(struct json_stream *response, - const char *fieldname, - const struct channel_id *cid) -{ - json_add_hex(response, fieldname, cid->id, sizeof(cid->id)); -} - -void json_add_pubkey(struct json_stream *response, - const char *fieldname, - const struct pubkey *key) -{ - u8 der[PUBKEY_CMPR_LEN]; - - pubkey_to_der(der, key); - json_add_hex(response, fieldname, der, sizeof(der)); -} - -void json_add_point32(struct json_stream *response, - const char *fieldname, - const struct point32 *key) -{ - u8 output[32]; - - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, &key->pubkey); - json_add_hex(response, fieldname, output, sizeof(output)); -} - -void json_add_bip340sig(struct json_stream *response, - const char *fieldname, - const struct bip340sig *sig) -{ - json_add_hex(response, fieldname, sig->u8, sizeof(sig->u8)); -} - -void json_add_txid(struct json_stream *result, const char *fieldname, - const struct bitcoin_txid *txid) -{ - char hex[hex_str_size(sizeof(*txid))]; - - bitcoin_txid_to_hex(txid, hex, sizeof(hex)); - json_add_string(result, fieldname, hex); -} - -void json_add_outpoint(struct json_stream *result, const char *fieldname, - const struct bitcoin_outpoint *out) -{ - char hex[hex_str_size(sizeof(out->txid))]; - bitcoin_txid_to_hex(&out->txid, hex, sizeof(hex)); - json_add_member(result, fieldname, true, "%s:%d", hex, out->n); -} - -void json_add_short_channel_id(struct json_stream *response, - const char *fieldname, - const struct short_channel_id *scid) -{ - json_add_member(response, fieldname, true, "%dx%dx%d", - short_channel_id_blocknum(scid), - short_channel_id_txnum(scid), - short_channel_id_outnum(scid)); -} - -void json_add_address(struct json_stream *response, const char *fieldname, - const struct wireaddr *addr) -{ - json_object_start(response, fieldname); - if (addr->type == ADDR_TYPE_IPV4) { - char addrstr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, addr->addr, addrstr, INET_ADDRSTRLEN); - json_add_string(response, "type", "ipv4"); - json_add_string(response, "address", addrstr); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_IPV6) { - char addrstr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr->addr, addrstr, INET6_ADDRSTRLEN); - json_add_string(response, "type", "ipv6"); - json_add_string(response, "address", addrstr); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V2_REMOVED) { - json_add_string(response, "type", "torv2"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V3) { - json_add_string(response, "type", "torv3"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_DNS) { - json_add_string(response, "type", "dns"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_WEBSOCKET) { - json_add_string(response, "type", "websocket"); - json_add_num(response, "port", addr->port); - } - json_object_end(response); -} - -void json_add_address_internal(struct json_stream *response, - const char *fieldname, - const struct wireaddr_internal *addr) -{ - switch (addr->itype) { - case ADDR_INTERNAL_SOCKNAME: - json_object_start(response, fieldname); - json_add_string(response, "type", "local socket"); - json_add_string(response, "socket", addr->u.sockname); - json_object_end(response); - return; - case ADDR_INTERNAL_ALLPROTO: - json_object_start(response, fieldname); - json_add_string(response, "type", "any protocol"); - json_add_num(response, "port", addr->u.port); - json_object_end(response); - return; - case ADDR_INTERNAL_AUTOTOR: - json_object_start(response, fieldname); - json_add_string(response, "type", "Tor generated address"); - json_add_address(response, "service", &addr->u.torservice.address); - json_object_end(response); - return; - case ADDR_INTERNAL_STATICTOR: - json_object_start(response, fieldname); - json_add_string(response, "type", "Tor from blob generated static address"); - json_add_address(response, "service", &addr->u.torservice.address); - json_object_end(response); - return; - case ADDR_INTERNAL_FORPROXY: - json_object_start(response, fieldname); - json_add_string(response, "type", "unresolved"); - json_add_string(response, "name", addr->u.unresolved.name); - json_add_num(response, "port", addr->u.unresolved.port); - json_object_end(response); - return; - case ADDR_INTERNAL_WIREADDR: - json_add_address(response, fieldname, &addr->u.wireaddr); - return; - } - abort(); -} - -void json_add_tx(struct json_stream *result, - const char *fieldname, - const struct bitcoin_tx *tx) -{ - json_add_hex_talarr(result, fieldname, linearize_tx(tmpctx, tx)); -} - -void json_add_psbt(struct json_stream *stream, - const char *fieldname, - const struct wally_psbt *psbt TAKES) -{ - const char *psbt_b64; - psbt_b64 = psbt_to_b64(NULL, psbt); - json_add_string(stream, fieldname, take(psbt_b64)); - if (taken(psbt)) - tal_free(psbt); -} - -void json_add_amount_msat_compat(struct json_stream *result, - struct amount_msat msat, - const char *rawfieldname, - const char *msatfieldname) -{ - if (deprecated_apis) - json_add_u64(result, rawfieldname, msat.millisatoshis); /* Raw: low-level helper */ - json_add_amount_msat_only(result, msatfieldname, msat); -} - -void json_add_amount_msat_only(struct json_stream *result, - const char *msatfieldname, - struct amount_msat msat) -{ - if (!deprecated_apis) - assert(strends(msatfieldname, "_msat")); - if (deprecated_apis) - json_add_string(result, msatfieldname, - type_to_string(tmpctx, struct amount_msat, &msat)); - else - json_add_u64(result, msatfieldname, msat.millisatoshis); /* Raw: low-level helper */ -} - -void json_add_amount_sat_compat(struct json_stream *result, - struct amount_sat sat, - const char *rawfieldname, - const char *msatfieldname) -{ - if (deprecated_apis) - json_add_u64(result, rawfieldname, sat.satoshis); /* Raw: low-level helper */ - json_add_amount_sat_msat(result, msatfieldname, sat); -} - -void json_add_amount_sat_msat(struct json_stream *result, - const char *msatfieldname, - struct amount_sat sat) -{ - struct amount_msat msat; - assert(strends(msatfieldname, "_msat")); - if (amount_sat_to_msat(&msat, sat)) - json_add_amount_msat_only(result, msatfieldname, msat); -} - -/* When I noticed that we were adding "XXXmsat" fields *not* ending in _msat */ -void json_add_amount_sats_deprecated(struct json_stream *result, - const char *fieldname, - const char *msatfieldname, - struct amount_sat sat) -{ - if (deprecated_apis) { - struct amount_msat msat; - assert(!strends(fieldname, "_msat")); - if (amount_sat_to_msat(&msat, sat)) - json_add_string(result, fieldname, - take(fmt_amount_msat(NULL, msat))); - } - json_add_amount_sat_msat(result, msatfieldname, sat); -} - -void json_add_sats(struct json_stream *result, - const char *fieldname, - struct amount_sat sat) -{ - json_add_string(result, fieldname, take(fmt_amount_sat(NULL, sat))); -} - -void json_add_secret(struct json_stream *response, const char *fieldname, - const struct secret *secret) -{ - json_add_hex(response, fieldname, secret, sizeof(struct secret)); -} - -void json_add_sha256(struct json_stream *result, const char *fieldname, - const struct sha256 *hash) -{ - json_add_hex(result, fieldname, hash, sizeof(*hash)); -} - -void json_add_preimage(struct json_stream *result, const char *fieldname, - const struct preimage *preimage) -{ - json_add_hex(result, fieldname, preimage, sizeof(*preimage)); -} - -void json_add_lease_rates(struct json_stream *result, - const struct lease_rates *rates) -{ - json_add_amount_sat_msat(result, "lease_fee_base_msat", - amount_sat(rates->lease_fee_base_sat)); - json_add_num(result, "lease_fee_basis", rates->lease_fee_basis); - json_add_num(result, "funding_weight", rates->funding_weight); - json_add_amount_msat_only(result, - "channel_fee_max_base_msat", - amount_msat(rates->channel_fee_max_base_msat)); - json_add_num(result, "channel_fee_max_proportional_thousandths", - rates->channel_fee_max_proportional_thousandths); -} diff --git a/common/json_helpers.h b/common/json_helpers.h deleted file mode 100644 index 9a6673db0..000000000 --- a/common/json_helpers.h +++ /dev/null @@ -1,208 +0,0 @@ -/* More specialized (bitcoin, lightning-specific) JSON helpers. */ -#ifndef LIGHTNING_COMMON_JSON_HELPERS_H -#define LIGHTNING_COMMON_JSON_HELPERS_H -#include "config.h" -#include -#include -#include -#include - -struct amount_msat; -struct amount_sat; -struct bip340sig; -struct channel_id; -struct lease_rates; -struct node_id; -struct preimage; -struct pubkey; -struct point32; -struct secret; -struct short_channel_id; -struct short_channel_id_dir; -struct wireaddr; -struct wireaddr_internal; -struct wally_psbt; - -/* Decode a hex-encoded payment preimage */ -bool json_to_preimage(const char *buffer, const jsmntok_t *tok, struct preimage *preimage); - -/* Extract a secret from this. */ -bool json_to_secret(const char *buffer, const jsmntok_t *tok, struct secret *dest); - -/* Extract a psbt from this. */ -struct wally_psbt *json_to_psbt(const tal_t *ctx, const char *buffer, - const jsmntok_t *tok); - -/* Extract a pubkey from this */ -bool json_to_pubkey(const char *buffer, const jsmntok_t *tok, - struct pubkey *pubkey); - -/* Extract node_id from this: makes sure *id is valid! */ -bool json_to_node_id(const char *buffer, const jsmntok_t *tok, - struct node_id *id); - -/* Extract satoshis from this (may be a string, or a decimal number literal) */ -bool json_to_bitcoin_amount(const char *buffer, const jsmntok_t *tok, - uint64_t *satoshi); - -/* Extract a short_channel_id from this */ -bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok, - struct short_channel_id *scid); - -/* Extract a satoshis amount from this */ -bool json_to_sat(const char *buffer, const jsmntok_t *tok, - struct amount_sat *sat); - -/* Extract a satoshis amount from this */ -/* If the string is "all", set amonut as AMOUNT_SAT(-1ULL). */ -bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok, - struct amount_sat *sat); - -/* Extract a millisatoshis amount from this */ -bool json_to_msat(const char *buffer, const jsmntok_t *tok, - struct amount_msat *msat); - -/* Extract a bitcoin txid from this */ -bool json_to_txid(const char *buffer, const jsmntok_t *tok, - struct bitcoin_txid *txid); - -/* Extract a bitcoin outpoint from this */ -bool json_to_outpoint(const char *buffer, const jsmntok_t *tok, - struct bitcoin_outpoint *op); - -/* Extract a channel id from this */ -bool json_to_channel_id(const char *buffer, const jsmntok_t *tok, - struct channel_id *cid); - -/* Extract a coin movement 'tag' from this */ -bool json_to_coin_mvt_tag(const char *buffer, const jsmntok_t *tok, - enum mvt_tag *tag); - -/* Split a json token into 2 tokens given a splitting character */ -bool split_tok(const char *buffer, const jsmntok_t *tok, - char split, - jsmntok_t *a, - jsmntok_t *b); - -/* Extract reply path from this JSON */ -struct tlv_onionmsg_payload_reply_path * -json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); - -/* Obsolete version! */ -struct tlv_obs2_onionmsg_payload_reply_path * -json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); - -/* Helpers for outputting JSON results */ - -/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ -void json_add_pubkey(struct json_stream *response, - const char *fieldname, - const struct pubkey *key); - -/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ -void json_add_point32(struct json_stream *response, - const char *fieldname, - const struct point32 *key); - -/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ -void json_add_bip340sig(struct json_stream *response, - const char *fieldname, - const struct bip340sig *sig); - -/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ -void json_add_secret(struct json_stream *response, - const char *fieldname, - const struct secret *secret); - -/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ -void json_add_node_id(struct json_stream *response, - const char *fieldname, - const struct node_id *id); - -/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ -void json_add_channel_id(struct json_stream *response, - const char *fieldname, - const struct channel_id *cid); - -/* '"fieldname" : ' or "" if fieldname is NULL */ -void json_add_txid(struct json_stream *result, const char *fieldname, - const struct bitcoin_txid *txid); - -/* '"fieldname" : "txid:n" */ -void json_add_outpoint(struct json_stream *result, const char *fieldname, - const struct bitcoin_outpoint *out); - -/* '"fieldname" : "1234:5:6"' */ -void json_add_short_channel_id(struct json_stream *response, - const char *fieldname, - const struct short_channel_id *id); - -/* JSON serialize a network address for a node */ -void json_add_address(struct json_stream *response, const char *fieldname, - const struct wireaddr *addr); - -/* JSON serialize a network address for a node. */ -void json_add_address_internal(struct json_stream *response, - const char *fieldname, - const struct wireaddr_internal *addr); - -/* Adds both a 'raw' number field and an 'amount_msat' field */ -void json_add_amount_msat_compat(struct json_stream *result, - struct amount_msat msat, - const char *rawfieldname, - const char *msatfieldname) - NO_NULL_ARGS; - -/* Adds both a 'raw' number field and an 'amount_msat' field */ -void json_add_amount_sat_compat(struct json_stream *result, - struct amount_sat sat, - const char *rawfieldname, - const char *msatfieldname) - NO_NULL_ARGS; - -/* Adds an 'msat' field */ -void json_add_amount_msat_only(struct json_stream *result, - const char *msatfieldname, - struct amount_msat msat) - NO_NULL_ARGS; - -/* Adds an 'msat' field */ -void json_add_amount_sat_msat(struct json_stream *result, - const char *msatfieldname, - struct amount_sat sat) - NO_NULL_ARGS; - -/* Adds an 'msat' field, and an older deprecated field. */ -void json_add_amount_sats_deprecated(struct json_stream *result, - const char *fieldname, - const char *msatfieldname, - struct amount_sat sat) - NO_NULL_ARGS; - -/* This is used to create requests, *never* for output (output is always - * msat!) */ -void json_add_sats(struct json_stream *result, - const char *fieldname, - struct amount_sat sat); - -void json_add_sha256(struct json_stream *result, const char *fieldname, - const struct sha256 *hash); - -void json_add_preimage(struct json_stream *result, const char *fieldname, - const struct preimage *preimage); - -/* '"fieldname" : "010000000001..."' or "010000000001..." if fieldname is NULL */ -void json_add_tx(struct json_stream *result, - const char *fieldname, - const struct bitcoin_tx *tx); - -/* '"fieldname" : "cHNidP8BAJoCAAAAAljo..." or "cHNidP8BAJoCAAAAAljo..." if fieldname is NULL */ -void json_add_psbt(struct json_stream *stream, - const char *fieldname, - const struct wally_psbt *psbt); - -/* Add fields from the lease_rates to a json stream. - * Note that field names are set */ -void json_add_lease_rates(struct json_stream *result, - const struct lease_rates *rates); -#endif /* LIGHTNING_COMMON_JSON_HELPERS_H */ diff --git a/common/json_tok.c b/common/json_param.c similarity index 69% rename from common/json_tok.c rename to common/json_param.c index 29a75884e..bf4ddc92e 100644 --- a/common/json_tok.c +++ b/common/json_param.c @@ -4,15 +4,378 @@ #include #include #include +#include #include +#include #include #include #include +#include #include -#include -#include +#include #include +struct param { + const char *name; + bool is_set; + enum param_style style; + param_cbx cbx; + void *arg; +}; + +static bool param_add(struct param **params, + const char *name, + enum param_style style, + param_cbx cbx, void *arg) +{ +#if DEVELOPER + if (!(name && cbx && arg)) + return false; +#endif + struct param last; + + last.is_set = false; + last.name = name; + last.style = style; + last.cbx = cbx; + last.arg = arg; + + tal_arr_expand(params, last); + return true; +} + +/* FIXME: To support the deprecated p_req_dup_ok */ +static bool is_required(enum param_style style) +{ + return style == PARAM_REQUIRED || style == PARAM_REQUIRED_ALLOW_DUPS; +} + +static struct command_result *make_callback(struct command *cmd, + struct param *def, + const char *buffer, + const jsmntok_t *tok) +{ + /* If it had a default, free that now to avoid leak */ + if (def->style == PARAM_OPTIONAL_WITH_DEFAULT && !def->is_set) + tal_free(*(void **)def->arg); + + def->is_set = true; + + return def->cbx(cmd, def->name, buffer, tok, def->arg); +} + +static struct command_result *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 && is_required(first->style)) { + if (!first->is_set) { + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "missing required parameter: %s", + first->name); + } + first++; + } + return NULL; +} + +static struct command_result *parse_by_position(struct command *cmd, + struct param *params, + const char *buffer, + const jsmntok_t tokens[], + bool allow_extra) +{ + struct command_result *res; + const jsmntok_t *tok; + size_t i; + + json_for_each_arr(i, tok, tokens) { + /* check for unexpected trailing params */ + if (i == tal_count(params)) { + if (!allow_extra) { + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "too many parameters:" + " got %u, expected %zu", + tokens->size, + tal_count(params)); + } + break; + } + + if (!json_tok_is_null(buffer, tok)) { + res = make_callback(cmd, params+i, buffer, tok); + if (res) + return res; + } + } + + 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) { + size_t arglen = strcspn(first->name, "|"); + if (memeq(first->name, arglen, start, n)) + return first; + if (deprecated_apis + && first->name[arglen] + && memeq(first->name + arglen + 1, + strlen(first->name + arglen + 1), + start, n)) + return first; + first++; + } + return NULL; +} + +static struct command_result *parse_by_name(struct command *cmd, + struct param *params, + const char *buffer, + const jsmntok_t tokens[], + bool allow_extra) +{ + size_t i; + const jsmntok_t *t; + + json_for_each_obj(i, t, tokens) { + struct param *p = find_param(params, buffer + t->start, + t->end - t->start); + if (!p) { + if (!allow_extra) { + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "unknown parameter: %.*s, this may be caused by a failure to autodetect key=value-style parameters. Please try using the -k flag and explicit key=value pairs of parameters.", + t->end - t->start, + buffer + t->start); + } + } else { + struct command_result *res; + + if (p->is_set) { + if (p->style == PARAM_REQUIRED_ALLOW_DUPS) + continue; + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "duplicate json names: %s", + p->name); + } + + res = make_callback(cmd, p, buffer, t + 1); + if (res) + return res; + } + } + 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 (!is_required(a->style) && is_required(b->style)) + 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_talarr(params, struct param, params); + + /* 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++) { + /* Don't print |deprecated part! */ + int len = strcspn(params[i].name, "|"); + if (i != 0) + tal_append_fmt(&usage, " "); + if (is_required(params[i].style)) + tal_append_fmt(&usage, "%.*s", len, params[i].name); + else + tal_append_fmt(&usage, "[%.*s]", len, params[i].name); + } + return usage; +} + +static struct command_result *param_arr(struct command *cmd, const char *buffer, + const jsmntok_t tokens[], + struct param *params, + bool allow_extra) +{ +#if DEVELOPER + if (!check_params(params)) { + return command_fail(cmd, PARAM_DEV_ERROR, + "developer error: check_params"); + } +#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); + + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Expected array or object for params"); +} + +const char *param_subcommand(struct command *cmd, const char *buffer, + const jsmntok_t tokens[], + const char *name, ...) +{ + va_list ap; + struct param *params = tal_arr(cmd, struct param, 0); + const char *arg, **names = tal_arr(tmpctx, const char *, 1); + const char *subcmd; + + param_add(¶ms, "subcommand", PARAM_REQUIRED, (void *)param_string, &subcmd); + names[0] = name; + va_start(ap, name); + while ((arg = va_arg(ap, const char *)) != NULL) + tal_arr_expand(&names, arg); + va_end(ap); + + if (command_usage_only(cmd)) { + char *usage = tal_strdup(cmd, "subcommand"); + for (size_t i = 0; i < tal_count(names); i++) + tal_append_fmt(&usage, "%c%s", + i == 0 ? '=' : '|', names[i]); + command_set_usage(cmd, usage); + return NULL; + } + + /* Check it's valid */ + if (param_arr(cmd, buffer, tokens, params, true) != NULL) { + return NULL; + } + + /* Check it's one of the known ones. */ + for (size_t i = 0; i < tal_count(names); i++) + if (streq(subcmd, names[i])) + return subcmd; + + /* We really do ignore this. */ + struct command_result *ignore; + ignore = command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Unknown subcommand '%s'", subcmd); + assert(ignore); + return NULL; +} + +bool param(struct command *cmd, const char *buffer, + const jsmntok_t tokens[], ...) +{ + struct param *params = tal_arr(tmpctx, 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) { + enum param_style style = va_arg(ap, enum param_style); + 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, style, cbx, arg)) { + /* We really do ignore this return! */ + struct command_result *ignore; + ignore = command_fail(cmd, PARAM_DEV_ERROR, + "developer error: param_add %s", name); + assert(ignore); + 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) == NULL + && !command_check_only(cmd); +} + struct command_result *param_array(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, const jsmntok_t **arr) diff --git a/common/json_tok.h b/common/json_param.h similarity index 61% rename from common/json_tok.h rename to common/json_param.h index 40bd32060..c08e466ad 100644 --- a/common/json_tok.h +++ b/common/json_param.h @@ -1,22 +1,152 @@ /* Helpers for use with param parsing. */ -#ifndef LIGHTNING_COMMON_JSON_TOK_H -#define LIGHTNING_COMMON_JSON_TOK_H +#ifndef LIGHTNING_COMMON_JSON_PARAM_H +#define LIGHTNING_COMMON_JSON_PARAM_H #include "config.h" #include #include -#include +#include #include #include #include #include +/*~ Greetings adventurer! + * + * Do you want to automatically validate json input and unmarshal 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 + * common/json_tok.c. Use them directly or feel free to write your own. + */ +struct command; + +/* A dummy type returned by command_ functions, to ensure you return them + * immediately */ +struct command_result; + +/* + * 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[], ...) LAST_ARG_NULL; + +/* + * The callback signature. + * + * Callbacks must return NULL on success. On failure they + * must return command_fail(...). + */ +typedef struct command_result *(*param_cbx)(struct command *cmd, + const char *name, + const char *buffer, + const jsmntok_t *tok, + void **arg); + +/** + * Parse the first json value. + * + * name...: NULL-terminated array of valid values. + * + * Returns subcommand: if it returns NULL if you should return + * command_param_failed() immediately. + */ +const char *param_subcommand(struct command *cmd, const char *buffer, + const jsmntok_t tokens[], + const char *name, ...) LAST_ARG_NULL; + +enum param_style { + PARAM_REQUIRED, + PARAM_REQUIRED_ALLOW_DUPS, + PARAM_OPTIONAL, + PARAM_OPTIONAL_WITH_DEFAULT, +}; + +/* + * Add a required parameter. + */ +#define p_req(name, cbx, arg) \ + name"", \ + PARAM_REQUIRED, \ + (param_cbx)(cbx), \ + (arg) + 0*sizeof((cbx)((struct command *)NULL, \ + (const char *)NULL, \ + (const char *)NULL, \ + (const jsmntok_t *)NULL, \ + (arg)) == (struct command_result *)NULL) + +/* + * Add an optional parameter. *arg is set to NULL if it isn't found. + */ +#define p_opt(name, cbx, arg) \ + name"", \ + PARAM_OPTIONAL, \ + (param_cbx)(cbx), \ + ({ *arg = NULL; \ + (arg) + 0*sizeof((cbx)((struct command *)NULL, \ + (const char *)NULL, \ + (const char *)NULL, \ + (const jsmntok_t *)NULL, \ + (arg)) == (struct command_result *)NULL); }) + +/* + * Add an required parameter, like p_req, but ignore duplicates. + */ +#define p_req_dup_ok(name, cbx, arg) \ + name"", \ + PARAM_REQUIRED_ALLOW_DUPS, \ + (param_cbx)(cbx), \ + ({ *arg = NULL; \ + (arg) + 0*sizeof((cbx)((struct command *)NULL, \ + (const char *)NULL, \ + (const char *)NULL, \ + (const jsmntok_t *)NULL, \ + (arg)) == (struct command_result *)NULL); }) + +/* + * Add an optional parameter. *arg is set to @def if it isn't found. + */ +#define p_opt_def(name, cbx, arg, def) \ + name"", \ + PARAM_OPTIONAL_WITH_DEFAULT, \ + (param_cbx)(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)) == (struct command_result *)NULL); }) + +/* Special flag for 'check' which allows any parameters. */ +#define p_opt_any() "", PARAM_OPTIONAL, NULL, NULL + +/* All the helper routines. */ struct amount_msat; struct amount_sat; struct bitcoin_txid; struct bitcoin_outpoint; struct channel_id; -struct command; -struct command_result; struct json_escape; struct route_exclusion; struct sha256; @@ -213,4 +343,4 @@ struct command_result *param_lease_hex(struct command *cmd, const char *buffer, const jsmntok_t *tok, struct lease_rates **rates); -#endif /* LIGHTNING_COMMON_JSON_TOK_H */ +#endif /* LIGHTNING_COMMON_JSON_PARAM_H */ diff --git a/common/json_parse.c b/common/json_parse.c new file mode 100644 index 000000000..74d46f21a --- /dev/null +++ b/common/json_parse.c @@ -0,0 +1,719 @@ +/* JSON core and helpers */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num) +{ + char *end; + long long l; + + l = strtoll(buffer + tok->start, &end, 0); + if (end != buffer + tok->end) + return false; + + BUILD_ASSERT(sizeof(l) >= sizeof(*num)); + *num = l; + + /* Check for overflow/underflow */ + if ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) + return false; + + /* Check if the number did not fit in `s64` (in case `long long` + is a bigger type). */ + if (*num != l) + return false; + + return true; +} + +bool json_to_millionths(const char *buffer, const jsmntok_t *tok, + u64 *millionths) +{ + int decimal_places = -1; + bool has_digits = 0; + + *millionths = 0; + for (int i = tok->start; i < tok->end; i++) { + if (isdigit(buffer[i])) { + has_digits = true; + /* Ignore too much precision */ + if (decimal_places >= 0 && ++decimal_places > 6) + continue; + if (mul_overflows_u64(*millionths, 10)) + return false; + *millionths *= 10; + if (add_overflows_u64(*millionths, buffer[i] - '0')) + return false; + *millionths += buffer[i] - '0'; + } else if (buffer[i] == '.') { + if (decimal_places != -1) + return false; + decimal_places = 0; + } else + return false; + } + + if (!has_digits) + return false; + + if (decimal_places == -1) + decimal_places = 0; + + while (decimal_places < 6) { + if (mul_overflows_u64(*millionths, 10)) + return false; + *millionths *= 10; + decimal_places++; + } + return true; +} + +bool json_to_number(const char *buffer, const jsmntok_t *tok, + unsigned int *num) +{ + uint64_t u64; + + if (!json_to_u64(buffer, tok, &u64)) + return false; + *num = u64; + + /* Just in case it doesn't fit. */ + if (*num != u64) + return false; + return true; +} + +bool json_to_u16(const char *buffer, const jsmntok_t *tok, + short unsigned int *num) +{ + uint64_t u64; + + if (!json_to_u64(buffer, tok, &u64)) + return false; + *num = u64; + + /* Just in case it doesn't fit. */ + if (*num != u64) + return false; + return true; +} + +bool json_to_int(const char *buffer, const jsmntok_t *tok, int *num) +{ + s64 tmp; + + if (!json_to_s64(buffer, tok, &tmp)) + return false; + *num = tmp; + + /* Just in case it doesn't fit. */ + if (*num != tmp) + return false; + + return true; +} + +bool json_to_errcode(const char *buffer, const jsmntok_t *tok, errcode_t *errcode) +{ + s64 tmp; + + if (!json_to_s64(buffer, tok, &tmp)) + return false; + *errcode = tmp; + + /* Just in case it doesn't fit. */ + if (*errcode != tmp) + return false; + + return true; +} + +bool json_to_sha256(const char *buffer, const jsmntok_t *tok, struct sha256 *dest) +{ + if (tok->type != JSMN_STRING) + return false; + + return hex_decode(buffer + tok->start, tok->end - tok->start, dest, + sizeof(struct sha256)); +} + +u8 *json_tok_bin_from_hex(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) +{ + u8 *result; + size_t hexlen, rawlen; + hexlen = tok->end - tok->start; + rawlen = hex_data_size(hexlen); + + result = tal_arr(ctx, u8, rawlen); + if (!hex_decode(buffer + tok->start, hexlen, result, rawlen)) + return tal_free(result); + + return result; +} + +/* talfmt take a ctx pointer and return NULL or a valid pointer. + * fmt takes the argument, and returns a bool. + * + * This function returns NULL on success, or errmsg on failure. +*/ +static const char *handle_percent(const char *buffer, + const jsmntok_t *tok, + va_list *ap) +{ + void *ctx; + const char *fmtname; + + /* This is set to (dummy) json_scan if it's a non-tal fmt */ + ctx = va_arg(*ap, void *); + fmtname = va_arg(*ap, const char *); + if (ctx != json_scan) { + void *(*talfmt)(void *, const char *, const jsmntok_t *); + void **p; + p = va_arg(*ap, void **); + talfmt = va_arg(*ap, void *(*)(void *, const char *, const jsmntok_t *)); + *p = talfmt(ctx, buffer, tok); + if (*p != NULL) + return NULL; + } else { + bool (*fmt)(const char *, const jsmntok_t *, void *); + void *p; + + p = va_arg(*ap, void *); + fmt = va_arg(*ap, bool (*)(const char *, const jsmntok_t *, void *)); + if (fmt(buffer, tok, p)) + return NULL; + } + + return tal_fmt(tmpctx, "%s could not parse %.*s", + fmtname, + json_tok_full_len(tok), + json_tok_full(buffer, tok)); +} + +/* GUIDE := OBJ | ARRAY | '%' + * OBJ := '{' FIELDLIST '}' + * FIELDLIST := FIELD [',' FIELD]* + * FIELD := LITERAL ':' FIELDVAL + * FIELDVAL := OBJ | ARRAY | LITERAL | '%' + * ARRAY := '[' ARRLIST ']' + * ARRLIST := ARRELEM [',' ARRELEM]* + * ARRELEM := NUMBER ':' FIELDVAL + */ + +static void parse_literal(const char **guide, + const char **literal, + size_t *len) +{ + *literal = *guide; + *len = strspn(*guide, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "_-"); + *guide += *len; +} + +static void parse_number(const char **guide, u32 *number) +{ + char *endp; + long int l; + + l = strtol(*guide, &endp, 10); + assert(endp != *guide); + assert(errno != ERANGE); + + /* Test for overflow */ + *number = l; + assert(*number == l); + + *guide = endp; +} + +static char guide_consume_one(const char **guide) +{ + char c = **guide; + (*guide)++; + return c; +} + +static void guide_must_be(const char **guide, char c) +{ + char actual = guide_consume_one(guide); + assert(actual == c); +} + +/* Recursion: return NULL on success, errmsg on fail */ +static const char *parse_obj(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap); + +static const char *parse_arr(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap); + +static const char *parse_guide(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const char *errmsg; + + if (**guide == '{') { + errmsg = parse_obj(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + } else if (**guide == '[') { + errmsg = parse_arr(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + } else { + guide_must_be(guide, '%'); + errmsg = handle_percent(buffer, tok, ap); + if (errmsg) + return errmsg; + } + return NULL; +} + +static const char *parse_fieldval(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const char *errmsg; + + if (**guide == '{') { + errmsg = parse_obj(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + } else if (**guide == '[') { + errmsg = parse_arr(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + } else if (**guide == '%') { + guide_consume_one(guide); + errmsg = handle_percent(buffer, tok, ap); + if (errmsg) + return errmsg; + } else { + const char *literal; + size_t len; + + /* Literal must match exactly (modulo quotes for strings) */ + parse_literal(guide, &literal, &len); + if (!memeq(buffer + tok->start, tok->end - tok->start, + literal, len)) { + return tal_fmt(tmpctx, + "%.*s does not match expected %.*s", + json_tok_full_len(tok), + json_tok_full(buffer, tok), + (int)len, literal); + } + } + return NULL; +} + +static const char *parse_field(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const jsmntok_t *member; + size_t len; + const char *memname; + + parse_literal(guide, &memname, &len); + guide_must_be(guide, ':'); + + member = json_get_membern(buffer, tok, memname, len); + if (!member) { + return tal_fmt(tmpctx, "object does not have member %.*s", + (int)len, memname); + } + + return parse_fieldval(buffer, member, guide, ap); +} + +static const char *parse_fieldlist(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + for (;;) { + const char *errmsg; + + errmsg = parse_field(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + if (**guide != ',') + break; + guide_consume_one(guide); + } + return NULL; +} + +static const char *parse_obj(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const char *errmsg; + + guide_must_be(guide, '{'); + + if (tok->type != JSMN_OBJECT) { + return tal_fmt(tmpctx, "token is not an object: %.*s", + json_tok_full_len(tok), + json_tok_full(buffer, tok)); + } + + errmsg = parse_fieldlist(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + + guide_must_be(guide, '}'); + return NULL; +} + +static const char *parse_arrelem(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const jsmntok_t *member; + u32 idx; + + parse_number(guide, &idx); + guide_must_be(guide, ':'); + + member = json_get_arr(tok, idx); + if (!member) { + return tal_fmt(tmpctx, "token has no index %u: %.*s", + idx, + json_tok_full_len(tok), + json_tok_full(buffer, tok)); + } + + return parse_fieldval(buffer, member, guide, ap); +} + +static const char *parse_arrlist(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const char *errmsg; + + for (;;) { + errmsg = parse_arrelem(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + if (**guide != ',') + break; + guide_consume_one(guide); + } + return NULL; +} + +static const char *parse_arr(const char *buffer, + const jsmntok_t *tok, + const char **guide, + va_list *ap) +{ + const char *errmsg; + + guide_must_be(guide, '['); + + if (tok->type != JSMN_ARRAY) { + return tal_fmt(tmpctx, "token is not an array: %.*s", + json_tok_full_len(tok), + json_tok_full(buffer, tok)); + } + + errmsg = parse_arrlist(buffer, tok, guide, ap); + if (errmsg) + return errmsg; + + guide_must_be(guide, ']'); + return NULL; +} + +const char *json_scanv(const tal_t *ctx, + const char *buffer, + const jsmntok_t *tok, + const char *guide, + va_list ap) +{ + va_list cpy; + const char *orig_guide = guide, *errmsg; + + /* We need this, since &ap doesn't work on some platforms... */ + va_copy(cpy, ap); + errmsg = parse_guide(buffer, tok, &guide, &cpy); + va_end(cpy); + + if (errmsg) { + return tal_fmt(ctx, "Parsing '%.*s': %s", + (int)(guide - orig_guide), orig_guide, + errmsg); + } + assert(guide[0] == '\0'); + return NULL; +} + +const char *json_scan(const tal_t *ctx, + const char *buffer, + const jsmntok_t *tok, + const char *guide, + ...) +{ + va_list ap; + const char *ret; + + va_start(ap, guide); + ret = json_scanv(ctx, buffer, tok, guide, ap); + va_end(ap); + return ret; +} + +bool json_to_bitcoin_amount(const char *buffer, const jsmntok_t *tok, + uint64_t *satoshi) +{ + char *end; + unsigned long btc, sat; + + btc = strtoul(buffer + tok->start, &end, 10); + if (btc == ULONG_MAX && errno == ERANGE) + return false; + if (end != buffer + tok->end) { + /* Expect always 8 decimal places. */ + if (*end != '.' || buffer + tok->end - end != 9) + return false; + sat = strtoul(end+1, &end, 10); + if (sat == ULONG_MAX && errno == ERANGE) + return false; + if (end != buffer + tok->end) + return false; + } else + sat = 0; + + *satoshi = btc * (uint64_t)100000000 + sat; + if (*satoshi != btc * (uint64_t)100000000 + sat) + return false; + + return true; +} + +bool json_to_node_id(const char *buffer, const jsmntok_t *tok, + struct node_id *id) +{ + return node_id_from_hexstr(buffer + tok->start, + tok->end - tok->start, id); +} + +bool json_to_pubkey(const char *buffer, const jsmntok_t *tok, + struct pubkey *pubkey) +{ + return pubkey_from_hexstr(buffer + tok->start, + tok->end - tok->start, pubkey); +} + +bool json_to_msat(const char *buffer, const jsmntok_t *tok, + struct amount_msat *msat) +{ + return parse_amount_msat(msat, + buffer + tok->start, tok->end - tok->start); +} + +bool json_to_sat(const char *buffer, const jsmntok_t *tok, + struct amount_sat *sat) +{ + return parse_amount_sat(sat, buffer + tok->start, tok->end - tok->start); +} + +bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok, + struct amount_sat *sat) +{ + if (json_tok_streq(buffer, tok, "all")) { + *sat = AMOUNT_SAT(-1ULL); + return true; + } + return json_to_sat(buffer, tok, sat); +} + +bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok, + struct short_channel_id *scid) +{ + return (short_channel_id_from_str(buffer + tok->start, + tok->end - tok->start, scid)); +} + +bool json_to_txid(const char *buffer, const jsmntok_t *tok, + struct bitcoin_txid *txid) +{ + return bitcoin_txid_from_hex(buffer + tok->start, + tok->end - tok->start, txid); +} + +bool json_to_outpoint(const char *buffer, const jsmntok_t *tok, + struct bitcoin_outpoint *op) +{ + jsmntok_t t1, t2; + + if (!split_tok(buffer, tok, ':', &t1, &t2)) + return false; + + return json_to_txid(buffer, &t1, &op->txid) + && json_to_u32(buffer, &t2, &op->n); +} + +bool json_to_channel_id(const char *buffer, const jsmntok_t *tok, + struct channel_id *cid) +{ + return hex_decode(buffer + tok->start, tok->end - tok->start, + cid, sizeof(*cid)); +} + +bool json_to_coin_mvt_tag(const char *buffer, const jsmntok_t *tok, + enum mvt_tag *tag) +{ + enum mvt_tag i_tag; + for (size_t i = 0; i < NUM_MVT_TAGS; i++) { + i_tag = (enum mvt_tag) i; + if (json_tok_streq(buffer, tok, mvt_tag_str(i_tag))) { + *tag = i_tag; + return true; + } + } + + return false; +} + +bool split_tok(const char *buffer, const jsmntok_t *tok, + char split, + jsmntok_t *a, + jsmntok_t *b) +{ + const char *p = memchr(buffer + tok->start, split, tok->end - tok->start); + if (!p) + return false; + + *a = *b = *tok; + a->end = p - buffer; + b->start = p + 1 - buffer; + + return true; +} + +bool json_to_secret(const char *buffer, const jsmntok_t *tok, struct secret *dest) +{ + return hex_decode(buffer + tok->start, tok->end - tok->start, + dest->data, sizeof(struct secret)); +} + +bool json_to_preimage(const char *buffer, const jsmntok_t *tok, struct preimage *preimage) +{ + size_t hexlen = tok->end - tok->start; + return hex_decode(buffer + tok->start, hexlen, preimage->r, sizeof(preimage->r)); +} + +struct wally_psbt *json_to_psbt(const tal_t *ctx, const char *buffer, + const jsmntok_t *tok) +{ + return psbt_from_b64(ctx, buffer + tok->start, tok->end - tok->start); +} + +struct tlv_obs2_onionmsg_payload_reply_path * +json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) +{ + struct tlv_obs2_onionmsg_payload_reply_path *rpath; + const jsmntok_t *hops, *t; + size_t i; + const char *err; + + rpath = tal(ctx, struct tlv_obs2_onionmsg_payload_reply_path); + err = json_scan(tmpctx, buffer, tok, "{blinding:%,first_node_id:%}", + JSON_SCAN(json_to_pubkey, &rpath->blinding), + JSON_SCAN(json_to_pubkey, &rpath->first_node_id), + NULL); + if (err) + return tal_free(rpath); + + hops = json_get_member(buffer, tok, "hops"); + if (!hops || hops->size < 1) + return tal_free(rpath); + + rpath->path = tal_arr(rpath, struct onionmsg_path *, hops->size); + json_for_each_arr(i, t, hops) { + rpath->path[i] = tal(rpath->path, struct onionmsg_path); + err = json_scan(tmpctx, buffer, t, "{id:%,encrypted_recipient_data:%}", + JSON_SCAN(json_to_pubkey, + &rpath->path[i]->node_id), + JSON_SCAN_TAL(rpath->path[i], + json_tok_bin_from_hex, + &rpath->path[i]->encrypted_recipient_data)); + if (err) + return tal_free(rpath); + } + + return rpath; +} + +struct tlv_onionmsg_payload_reply_path * +json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) +{ + struct tlv_onionmsg_payload_reply_path *rpath; + const jsmntok_t *hops, *t; + size_t i; + const char *err; + + rpath = tal(ctx, struct tlv_onionmsg_payload_reply_path); + err = json_scan(tmpctx, buffer, tok, "{blinding:%,first_node_id:%}", + JSON_SCAN(json_to_pubkey, &rpath->blinding), + JSON_SCAN(json_to_pubkey, &rpath->first_node_id), + NULL); + if (err) + return tal_free(rpath); + + hops = json_get_member(buffer, tok, "hops"); + if (!hops || hops->size < 1) + return tal_free(rpath); + + rpath->path = tal_arr(rpath, struct onionmsg_path *, hops->size); + json_for_each_arr(i, t, hops) { + rpath->path[i] = tal(rpath->path, struct onionmsg_path); + err = json_scan(tmpctx, buffer, t, "{id:%,encrypted_recipient_data:%}", + JSON_SCAN(json_to_pubkey, + &rpath->path[i]->node_id), + JSON_SCAN_TAL(rpath->path[i], + json_tok_bin_from_hex, + &rpath->path[i]->encrypted_recipient_data)); + if (err) + return tal_free(rpath); + } + + return rpath; +} diff --git a/common/json_parse.h b/common/json_parse.h new file mode 100644 index 000000000..636ac4d8b --- /dev/null +++ b/common/json_parse.h @@ -0,0 +1,156 @@ +#ifndef LIGHTNING_COMMON_JSON_PARSE_H +#define LIGHTNING_COMMON_JSON_PARSE_H +#include "config.h" +#include +#include +#include +/* Simple helpers are here: this file contains heavier ones */ +#include + +struct json_escape; +struct json_stream; +struct timeabs; +struct timespec; +struct preimage; +struct secret; +struct pubkey; +struct node_id; +struct short_channel_id; +struct amount_sat; +struct amount_msat; +struct bitcoin_txid; +struct bitcoin_outpoint; +struct channel_id; + +/* Decode a hex-encoded binary */ +u8 *json_tok_bin_from_hex(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); + +/* Extract number from this (may be a string, or a number literal) */ +bool json_to_number(const char *buffer, const jsmntok_t *tok, + unsigned int *num); + +/* Extract signed 64 bit integer from this (may be a string, or a number literal) */ +bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num); + +/* Extract number from this (may be a string, or a number literal) */ +bool json_to_u16(const char *buffer, const jsmntok_t *tok, + uint16_t *num); + +bool json_to_sha256(const char *buffer, const jsmntok_t *tok, struct sha256 *dest); +/* + * Extract a non-negative (either 0 or positive) floating-point number from this + * (must be a number literal), multiply it by 1 million and return it as an + * integer. Any fraction smaller than 0.000001 is ignored. + */ +bool json_to_millionths(const char *buffer, const jsmntok_t *tok, + u64 *millionths); + +/* Extract signed integer from this (may be a string, or a number literal) */ +bool json_to_int(const char *buffer, const jsmntok_t *tok, int *num); + +/* Extract an error code from this (may be a string, or a number literal) */ +bool json_to_errcode(const char *buffer, const jsmntok_t *tok, errcode_t *errcode); + +/* Split a json token into 2 tokens given a splitting character */ +bool split_tok(const char *buffer, const jsmntok_t *tok, + char split, + jsmntok_t *a, + jsmntok_t *b); + +/* Decode a hex-encoded payment preimage */ +bool json_to_preimage(const char *buffer, const jsmntok_t *tok, struct preimage *preimage); + +/* Extract a secret from this. */ +bool json_to_secret(const char *buffer, const jsmntok_t *tok, struct secret *dest); + +/* Extract a psbt from this. */ +struct wally_psbt *json_to_psbt(const tal_t *ctx, const char *buffer, + const jsmntok_t *tok); + +/* Extract a pubkey from this */ +bool json_to_pubkey(const char *buffer, const jsmntok_t *tok, + struct pubkey *pubkey); + +/* Extract node_id from this: makes sure *id is valid! */ +bool json_to_node_id(const char *buffer, const jsmntok_t *tok, + struct node_id *id); + +/* Extract satoshis from this (may be a string, or a decimal number literal) */ +bool json_to_bitcoin_amount(const char *buffer, const jsmntok_t *tok, + uint64_t *satoshi); + +/* Extract a short_channel_id from this */ +bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok, + struct short_channel_id *scid); + +/* Extract a satoshis amount from this */ +bool json_to_sat(const char *buffer, const jsmntok_t *tok, + struct amount_sat *sat); + +/* Extract a satoshis amount from this */ +/* If the string is "all", set amonut as AMOUNT_SAT(-1ULL). */ +bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok, + struct amount_sat *sat); + +/* Extract a millisatoshis amount from this */ +bool json_to_msat(const char *buffer, const jsmntok_t *tok, + struct amount_msat *msat); + +/* Extract a bitcoin txid from this */ +bool json_to_txid(const char *buffer, const jsmntok_t *tok, + struct bitcoin_txid *txid); + +/* Extract a bitcoin outpoint from this */ +bool json_to_outpoint(const char *buffer, const jsmntok_t *tok, + struct bitcoin_outpoint *op); + +/* Extract a channel id from this */ +bool json_to_channel_id(const char *buffer, const jsmntok_t *tok, + struct channel_id *cid); + +/* Extract a coin movement 'tag' from this */ +bool json_to_coin_mvt_tag(const char *buffer, const jsmntok_t *tok, + enum mvt_tag *tag); + +/* Extract reply path from this JSON */ +struct tlv_onionmsg_payload_reply_path * +json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); + +/* Obsolete version! */ +struct tlv_obs2_onionmsg_payload_reply_path * +json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); + + +/* Guide is % for a token: each must be followed by JSON_SCAN(). + * Returns NULL on error (asserts() on bad guide). */ +const char *json_scan(const tal_t *ctx, + const char *buffer, + const jsmntok_t *tok, + const char *guide, + ...); + +/* eg. JSON_SCAN(json_to_bool, &boolvar) */ +#define JSON_SCAN(fmt, var) \ + json_scan, \ + stringify(fmt), \ + ((var) + 0*sizeof(fmt((const char *)NULL, \ + (const jsmntok_t *)NULL, var) == true)), \ + (fmt) + +/* eg. JSON_SCAN_TAL(tmpctx, json_strdup, &charvar) */ +#define JSON_SCAN_TAL(ctx, fmt, var) \ + (ctx), \ + stringify(fmt), \ + ((var) + 0*sizeof((*var) = fmt((ctx), \ + (const char *)NULL, \ + (const jsmntok_t *)NULL))), \ + (fmt) + +/* Already-have-varargs version */ +const char *json_scanv(const tal_t *ctx, + const char *buffer, + const jsmntok_t *tok, + const char *guide, + va_list ap); + +#endif /* LIGHTNING_COMMON_JSON_PARSE_H */ diff --git a/common/json_parse_simple.c b/common/json_parse_simple.c new file mode 100644 index 000000000..cf781611e --- /dev/null +++ b/common/json_parse_simple.c @@ -0,0 +1,552 @@ +/* JSON core and helpers */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *json_tok_full(const char *buffer, const jsmntok_t *t) +{ + if (t->type == JSMN_STRING) + return buffer + t->start - 1; + return buffer + t->start; +} + +/* Include " if it's a string. */ +int json_tok_full_len(const jsmntok_t *t) +{ + if (t->type == JSMN_STRING) + return t->end - t->start + 2; + return t->end - t->start; +} + +bool json_tok_strneq(const char *buffer, const jsmntok_t *tok, + const char *str, size_t len) +{ + if (tok->type != JSMN_STRING) + return false; + return memeq(buffer + tok->start, tok->end - tok->start, str, len); +} + +bool json_tok_streq(const char *buffer, const jsmntok_t *tok, const char *str) +{ + return json_tok_strneq(buffer, tok, str, strlen(str)); +} + +bool json_tok_startswith(const char *buffer, const jsmntok_t *tok, + const char *prefix) +{ + if (tok->type != JSMN_STRING) + return false; + if (tok->end - tok->start < strlen(prefix)) + return false; + return memcmp(buffer + tok->start, + prefix, strlen(prefix)) == 0; +} + +bool json_tok_endswith(const char *buffer, const jsmntok_t *tok, + const char *suffix) +{ + if (tok->type != JSMN_STRING) + return false; + if (tok->end - tok->start < strlen(suffix)) + return false; + return memcmp(buffer + tok->end - strlen(suffix), + suffix, strlen(suffix)) == 0; +} + +char *json_strdup(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) +{ + return tal_strndup(ctx, buffer + tok->start, tok->end - tok->start); +} + + +bool json_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num) +{ + char *end; + unsigned long long l; + + l = strtoull(buffer + tok->start, &end, 0); + if (end != buffer + tok->end) + return false; + + BUILD_ASSERT(sizeof(l) >= sizeof(*num)); + *num = l; + + /* Check for overflow */ + if (l == ULLONG_MAX && errno == ERANGE) + return false; + + if (*num != l) + return false; + + return true; +} + +bool json_to_u32(const char *buffer, const jsmntok_t *tok, u32 *num) +{ + uint64_t u64; + + if (!json_to_u64(buffer, tok, &u64)) + return false; + *num = u64; + + /* Just in case it doesn't fit. */ + if (*num != u64) + return false; + return true; +} + +bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b) +{ + if (tok->type != JSMN_PRIMITIVE) + return false; + 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; + } + return false; +} + + +bool json_tok_is_num(const char *buffer, const jsmntok_t *tok) +{ + if (tok->type != JSMN_PRIMITIVE) + return false; + + for (int i = tok->start; i < tok->end; i++) + if (!cisdigit(buffer[i])) + return false; + return true; +} + +bool json_tok_is_null(const char *buffer, const jsmntok_t *tok) +{ + if (tok->type != JSMN_PRIMITIVE) + return false; + return buffer[tok->start] == 'n'; +} + +const jsmntok_t *json_next(const jsmntok_t *tok) +{ + const jsmntok_t *t; + size_t i; + + for (t = tok + 1, i = 0; i < tok->size; i++) + t = json_next(t); + + return t; +} + +const jsmntok_t *json_get_membern(const char *buffer, + const jsmntok_t tok[], + const char *label, size_t len) +{ + const jsmntok_t *t; + size_t i; + + if (tok->type != JSMN_OBJECT) + return NULL; + + json_for_each_obj(i, t, tok) + if (json_tok_strneq(buffer, t, label, len)) + return t + 1; + + return NULL; +} + +const jsmntok_t *json_get_member(const char *buffer, const jsmntok_t tok[], + const char *label) +{ + return json_get_membern(buffer, tok, label, strlen(label)); +} + +const jsmntok_t *json_get_arr(const jsmntok_t tok[], size_t index) +{ + const jsmntok_t *t; + size_t i; + + if (tok->type != JSMN_ARRAY) + return NULL; + + json_for_each_arr(i, t, tok) { + if (index == 0) + return t; + index--; + } + + return NULL; +} + +/*----------------------------------------------------------------------------- +JSMN Result Validation Starts +-----------------------------------------------------------------------------*/ +/*~ LIBJSMN is a fast, small JSON parsing library. + * + * "Fast, small" means it does not, in fact, do a + * lot of checking for invalid JSON. + * + * For example, by itself it would accept the strings + * `{"1" "2" "3" "4"}` and `["key": 1 2 3 4]` as valid. + * Obviously those are not in any way valid JSON. + * + * This part of the code performs some filtering so + * that at least some of the invalid JSON that + * LIBJSMN accepts, will be rejected by + * json_parse_input. It also checks that strings are valid UTF-8. + */ + +/*~ These functions are used in JSMN validation. + * + * The calling convention is that the "current" token + * is passed in as the first argument, and after the + * validator, is returned from the function. + * + * p = validate_jsmn_datum(p, end, valid); + * + * The reason has to do with typical C ABIs. + * Usually, the first few arguments are passed in via + * register, and the return value is also returned + * via register. + * This calling convention generally ensures that + * the current token pointer `p` is always in a + * register and is never forced into memory by the + * compiler. + * + * These functions are pre-declared here as they + * are interrecursive. + * Note that despite the recursion, `p` is only ever + * advanced, and there is only ever one `p` value, + * thus the overall algorithm is strict O(n) + * (*not* amortized) in time. + * The recursion does mean the algorithm is O(d) + * in memory (specifically stack frames), where d + * is the nestedness of objects in the input. + * This may become an issue later if we are in a + * stack-limited environment, such as if we actually + * went and used threads. + */ +/* Validate a *single* datum. */ +static const jsmntok_t * +validate_jsmn_datum(const char *buf, + const jsmntok_t *p, + const jsmntok_t *end, + bool *valid); +/*~ Validate a key-value pair. + * + * In JSMN, objects are not dictionaries. + * Instead, they are a sequence of datums. + * + * In fact, objects and arrays in JSMN are "the same", + * they only differ in delimiter characters. + * + * Of course, in "real" JSON, an object is a dictionary + * of key-value pairs. + * + * So what JSMN does is that the syntax "key": "value" + * is considered a *single* datum, a string "key" + * that contains a value "value". + * + * Indeed, JSMN accepts `["key": "value"]` as well as + * `{"item1", "item2"}`. + * The entire point of the validate_jsmn_result function + * is to reject such improper arrays and objects. + */ +static const jsmntok_t * +validate_jsmn_keyvalue(const char *buf, + const jsmntok_t *p, + const jsmntok_t *end, + bool *valid); + +static const jsmntok_t * +validate_jsmn_datum(const char *buf, + const jsmntok_t *p, + const jsmntok_t *end, + bool *valid) +{ + int i; + int sz; + + if (p >= end) { + *valid = false; + return p; + } + + switch (p->type) { + case JSMN_STRING: + if (!utf8_check(buf + p->start, p->end - p->start)) + *valid = false; + /* Fall thru */ + case JSMN_UNDEFINED: + case JSMN_PRIMITIVE: + /* These types should not have sub-datums. */ + if (p->size != 0) + *valid = false; + else + ++p; + break; + + case JSMN_ARRAY: + /* Save the array size; we will advance p. */ + sz = p->size; + ++p; + for (i = 0; i < sz; ++i) { + /* Arrays should only contain standard JSON datums. */ + p = validate_jsmn_datum(buf, p, end, valid); + if (!*valid) + break; + } + break; + + case JSMN_OBJECT: + /* Save the object size; we will advance p. */ + sz = p->size; + ++p; + for (i = 0; i < sz; ++i) { + /* Objects should only contain key-value pairs. */ + p = validate_jsmn_keyvalue(buf, p, end, valid); + if (!*valid) + break; + } + break; + + default: + *valid = false; + break; + } + + return p; +} +/* Key-value pairs *must* be strings with size 1. */ +static inline const jsmntok_t * +validate_jsmn_keyvalue(const char *buf, + const jsmntok_t *p, + const jsmntok_t *end, + bool *valid) +{ + if (p >= end) { + *valid = false; + return p; + } + + /* Check key. + * + * JSMN parses the syntax `"key": "value"` as a + * JSMN_STRING of size 1, containing the value + * datum as a sub-datum. + * + * Thus, keys in JSON objects are really strings + * that "contain" the value, thus we check if + * the size is 1. + * + * JSMN supports a non-standard syntax such as + * `"key": 1 2 3 4`, which it considers as a + * string object that contains a sequence of + * sub-datums 1 2 3 4. + * The check below that p->size == 1 also + * incidentally rejects that non-standard + * JSON. + */ + if (p->type != JSMN_STRING || p->size != 1 + || !utf8_check(buf + p->start, p->end - p->start)) { + *valid = false; + return p; + } + + ++p; + return validate_jsmn_datum(buf, p, end, valid); +} + +/** validate_jsmn_parse_output + * + * @brief Validates the result of jsmn_parse. + * + * @desc LIBJMSN is a small fast library, not a + * comprehensive library. + * + * This simply means that LIBJSMN will accept a + * *lot* of very strange text that is technically + * not JSON. + * + * For example, LIBJSMN would accept the strings + * `{"1" "2" "3" "4"}` and `["key": 1 2 3 4]` as valid. + * + * This can lead to strange sequences of jsmntok_t + * objects. + * Unfortunately, most of our code assumes that + * the data fed into our JSON-RPC interface is + * valid JSON, and in particular is not invalid + * JSON that tickles LIBJSMN into emitting + * strange sequences of `jsmntok_t`. + * + * This function detects such possible problems + * and returns false if such an issue is found. + * If so, it is probably unsafe to pass the + * `jsmntok_t` generated by LIBJSMN to any other + * parts of our code. + * + * @param p - The first jsmntok_t token to process. + * This function does not assume that semantically + * only one JSON datum is processed; it does expect + * a sequence of complete JSON datums (which is + * what LIBJSMN *should* output). + * @param end - One past the end of jsmntok_t. + * Basically, this function is assured to read tokens + * starting at p up to end - 1. + * If p >= end, this will not validate anything and + * trivially return true. + * + * @return true if there appears to be no problem + * with the jsmntok_t sequence outputted by + * `jsmn_parse`, false otherwise. + */ +static bool +validate_jsmn_parse_output(const char *buf, + const jsmntok_t *p, const jsmntok_t *end) +{ + bool valid = true; + + while (p < end && valid) + p = validate_jsmn_datum(buf, p, end, &valid); + + return valid; +} + +/*----------------------------------------------------------------------------- +JSMN Result Validation Ends +-----------------------------------------------------------------------------*/ + +void toks_reset(jsmntok_t *toks) +{ + assert(tal_count(toks) >= 1); + toks[0].type = JSMN_UNDEFINED; +} + +jsmntok_t *toks_alloc(const tal_t *ctx) +{ + jsmntok_t *toks = tal_arr(ctx, jsmntok_t, 10); + toks_reset(toks); + return toks; +} + +bool json_parse_input(jsmn_parser *parser, + jsmntok_t **toks, + const char *input, int len, + bool *complete) +{ + int ret; + +again: + ret = jsmn_parse(parser, input, len, *toks, tal_count(*toks) - 1); + + switch (ret) { + case JSMN_ERROR_INVAL: + return false; + case JSMN_ERROR_NOMEM: + tal_resize(toks, tal_count(*toks) * 2); + goto again; + } + + /* Check whether we read at least one full root element, i.e., root + * element has its end set. */ + if ((*toks)[0].type == JSMN_UNDEFINED || (*toks)[0].end == -1) { + *complete = false; + return true; + } + + /* If we read a partial element at the end of the stream we'll get a + * ret=JSMN_ERROR_PART, but due to the previous check we know we read at + * least one full element, so count tokens that are part of this root + * element. */ + ret = json_next(*toks) - *toks; + + if (!validate_jsmn_parse_output(input, *toks, *toks + ret)) + return false; + + /* Cut to length and return. */ + tal_resize(toks, ret + 1); + /* Make sure last one is always referenceable. */ + (*toks)[ret].type = -1; + (*toks)[ret].start = (*toks)[ret].end = (*toks)[ret].size = 0; + + *complete = true; + return true; +} + +jsmntok_t *json_parse_simple(const tal_t *ctx, const char *input, int len) +{ + bool complete; + jsmn_parser parser; + jsmntok_t *toks = toks_alloc(ctx); + + jsmn_init(&parser); + + if (!json_parse_input(&parser, &toks, input, len, &complete) + || !complete) + return tal_free(toks); + return toks; +} + +const char *jsmntype_to_string(jsmntype_t t) +{ + switch (t) { + case JSMN_UNDEFINED : + return "UNDEFINED"; + case JSMN_OBJECT : + return "OBJECT"; + case JSMN_ARRAY : + return "ARRAY"; + case JSMN_STRING : + return "STRING"; + case JSMN_PRIMITIVE : + return "PRIMITIVE"; + } + return "INVALID"; +} + +jsmntok_t *json_tok_copy(const tal_t *ctx, const jsmntok_t *tok) +{ + return tal_dup_arr(ctx, jsmntok_t, tok, json_next(tok) - tok, 0); +} + +void json_tok_remove(jsmntok_t **tokens, + jsmntok_t *obj_or_array, const jsmntok_t *tok, size_t num) +{ + const jsmntok_t *src = tok; + const jsmntok_t *end = json_next(*tokens); + jsmntok_t *dest = *tokens + (tok - *tokens); + int remove_count; + + assert(*tokens); + assert(obj_or_array->type == JSMN_ARRAY + || obj_or_array->type == JSMN_OBJECT); + /* obj_or_array must be inside tokens, and tok must be inside + * obj_or_array */ + assert(obj_or_array >= *tokens + && obj_or_array < *tokens + tal_count(*tokens)); + assert(tok >= obj_or_array + && tok < *tokens + tal_count(*tokens)); + + for (int i = 0; i < num; i++) + src = json_next(src); + + /* Don't give us a num which goes over end of obj_or_array. */ + assert(src <= json_next(obj_or_array)); + + remove_count = src - tok; + + memmove(dest, src, sizeof(jsmntok_t) * (end - src)); + + /* Subtract first: this ptr may move after tal_resize! */ + obj_or_array->size -= num; + tal_resize(tokens, tal_count(*tokens) - remove_count); +} diff --git a/common/json_parse_simple.h b/common/json_parse_simple.h new file mode 100644 index 000000000..d0670b013 --- /dev/null +++ b/common/json_parse_simple.h @@ -0,0 +1,122 @@ +/* Very simple core JSON parse helpers: used by lightning-cli too */ +#ifndef LIGHTNING_COMMON_JSON_PARSE_SIMPLE_H +#define LIGHTNING_COMMON_JSON_PARSE_SIMPLE_H +#include "config.h" +#include +#include + +#define JSMN_STRICT 1 +# include + +/* Include " if it's a string. */ +const char *json_tok_full(const char *buffer, const jsmntok_t *t); + +/* Include " if it's a string. */ +int json_tok_full_len(const jsmntok_t *t); + +/* Is this a string equal to str? */ +bool json_tok_streq(const char *buffer, const jsmntok_t *tok, const char *str); + +/* Is this a string equal to str of length len? */ +bool json_tok_strneq(const char *buffer, const jsmntok_t *tok, + const char *str, size_t len); + +/* Does this string token start with prefix? */ +bool json_tok_startswith(const char *buffer, const jsmntok_t *tok, + const char *prefix); + +/* Does this string token end with suffix? */ +bool json_tok_endswith(const char *buffer, const jsmntok_t *tok, + const char *suffix); + +/* Allocate a tal string copy */ +char *json_strdup(const tal_t *ctx, const char *buffer, const jsmntok_t *tok); + +/* Extract number from this (may be a string, or a number literal) */ +bool json_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num); + +/* Extract number from this (may be a string, or a number literal) */ +bool json_to_u32(const char *buffer, const jsmntok_t *tok, u32 *num); + +/* Extract boolean from this */ +bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b); + +/* Is this a number? [0..9]+ */ +bool json_tok_is_num(const char *buffer, const jsmntok_t *tok); + +/* Is this the null primitive? */ +bool json_tok_is_null(const char *buffer, const jsmntok_t *tok); + +/* Returns next token with same parent (WARNING: slow!). */ +const jsmntok_t *json_next(const jsmntok_t *tok); + +/* Get top-level member with explicit label len */ +const jsmntok_t *json_get_membern(const char *buffer, + const jsmntok_t tok[], + const char *label, size_t len); + +/* Get top-level member. */ +const jsmntok_t *json_get_member(const char *buffer, const jsmntok_t tok[], + const char *label); + +/* Get index'th array member. */ +const jsmntok_t *json_get_arr(const jsmntok_t tok[], size_t index); + +/* Allocate a starter array of tokens for json_parse_input */ +jsmntok_t *toks_alloc(const tal_t *ctx); + +/* Reset a token array to reuse it. */ +void toks_reset(jsmntok_t *toks); + +/** + * json_parse_input: parse and validate JSON. + * @parser: parser initialized with jsmn_init. + * @toks: tallocated array from toks_alloc() + * @input, @len: input string. + * @complete: set to true if the valid JSON is complete, or NULL if must be. + * + * This returns false if the JSON is invalid, true otherwise. + * If it returns true, *@complete indicates that (*@toks)[0] points to a + * valid, complete JSON element. If @complete is NULL, then incomplete + * JSON returns false (i.e. is considered invalid). + * + * *@toks is resized to the complete set of tokens, with a dummy + * terminator (type == -1) at the end. + * + * If it returns true, and *@complete is false, you can append more + * data to @input and call it again (with the same perser) and the parser + * will continue where it left off. +*/ +bool json_parse_input(jsmn_parser *parser, + jsmntok_t **toks, + const char *input, int len, + bool *complete); + +/* Simplified version of above which parses only a complete, valid + * JSON string */ +jsmntok_t *json_parse_simple(const tal_t *ctx, const char *input, int len); + +/* Convert a jsmntype_t enum to a human readable string. */ +const char *jsmntype_to_string(jsmntype_t t); + +/* Return a copy of a json value as an array. */ +jsmntok_t *json_tok_copy(const tal_t *ctx, const jsmntok_t *tok); + +/* + * Remove @num json values from a json array or object @obj. @tok points + * to the first value to remove. The array @tokens will be resized. + */ +void json_tok_remove(jsmntok_t **tokens, + jsmntok_t *obj_or_array, const jsmntok_t *tok, size_t num); + + +/* Iterator macro for array: i is counter, t is token ptr, arr is JSMN_ARRAY */ +#define json_for_each_arr(i, t, arr) \ + for (i = 0, t = (arr) + 1; i < (arr)->size; t = json_next(t), i++) + +/* Iterator macro for object: i is counter, t is token ptr (t+1 is + * contents of obj member), obj is JSMN_OBJECT */ +#define json_for_each_obj(i, t, obj) \ + for (i = 0, t = (obj) + 1; i < (obj)->size; t = json_next(t+1), i++) + +#endif /* LIGHTNING_COMMON_JSON_PARSE_SIMPLE_H */ diff --git a/common/json_stream.c b/common/json_stream.c index 8ec5fefdc..740defa7c 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -1,10 +1,28 @@ #include "config.h" +#include +#include +#include +#include +#include +#include +#include #include /* To reach into io_plan: not a public header! */ #include +#include #include +#include +#include +#include +#include #include - +#include +#include +#include +#include +#include +#include +#include static void adjust_io_write(struct json_out *jout, ptrdiff_t delta, @@ -204,3 +222,419 @@ struct io_plan *json_stream_output_(struct json_stream *js, js->len_read = 0; return json_stream_output_write(conn, js); } + +void json_add_num(struct json_stream *result, const char *fieldname, unsigned int value) +{ + json_add_member(result, fieldname, false, "%u", value); +} + +void json_add_u64(struct json_stream *result, const char *fieldname, + uint64_t value) +{ + json_add_member(result, fieldname, false, "%"PRIu64, value); +} + +void json_add_s64(struct json_stream *result, const char *fieldname, + int64_t value) +{ + json_add_member(result, fieldname, false, "%"PRIi64, value); +} + +void json_add_u32(struct json_stream *result, const char *fieldname, + uint32_t value) +{ + json_add_member(result, fieldname, false, "%u", value); +} + +void json_add_s32(struct json_stream *result, const char *fieldname, + int32_t value) +{ + json_add_member(result, fieldname, false, "%d", value); +} + +void json_add_literal(struct json_stream *result, const char *fieldname, + const char *literal, int len) +{ + /* Literal may contain quotes, so bypass normal checks */ + char *dest = json_member_direct(result, fieldname, len); + memcpy(dest, literal, len); +} + +void json_add_stringn(struct json_stream *result, const char *fieldname, + const char *value TAKES, size_t value_len) +{ + json_add_member(result, fieldname, true, "%.*s", (int)value_len, value); + if (taken(value)) + tal_free(value); +} + +void json_add_string(struct json_stream *result, const char *fieldname, const char *value TAKES) +{ + json_add_stringn(result, fieldname, value, strlen(value)); +} + +void json_add_bool(struct json_stream *result, const char *fieldname, bool value) +{ + json_add_member(result, fieldname, false, value ? "true" : "false"); +} + +void json_add_null(struct json_stream *stream, const char *fieldname) +{ + json_add_member(stream, fieldname, false, "null"); +} + +void json_add_hex(struct json_stream *js, const char *fieldname, + const void *data, size_t len) +{ + /* Size without NUL term */ + size_t hexlen = hex_str_size(len) - 1; + char *dest; + + dest = json_member_direct(js, fieldname, 1 + hexlen + 1); + dest[0] = '"'; + if (!hex_encode(data, len, dest + 1, hexlen + 1)) + abort(); + dest[1+hexlen] = '"'; +} + +void json_add_hex_talarr(struct json_stream *result, + const char *fieldname, + const tal_t *data) +{ + json_add_hex(result, fieldname, data, tal_bytelen(data)); +} + +void json_add_escaped_string(struct json_stream *result, const char *fieldname, + const struct json_escape *esc TAKES) +{ + /* Already escaped, don't re-escape! */ + char *dest = json_member_direct(result, fieldname, + 1 + strlen(esc->s) + 1); + + dest[0] = '"'; + memcpy(dest + 1, esc->s, strlen(esc->s)); + dest[1+strlen(esc->s)] = '"'; + if (taken(esc)) + tal_free(esc); +} + +void json_add_timeabs(struct json_stream *result, const char *fieldname, + struct timeabs t) +{ + json_add_member(result, fieldname, false, "%" PRIu64 ".%03" PRIu64, + (u64)t.ts.tv_sec, (u64)t.ts.tv_nsec / 1000000); +} + +void json_add_time(struct json_stream *result, const char *fieldname, + struct timespec ts) +{ + char timebuf[100]; + + snprintf(timebuf, sizeof(timebuf), "%lu.%09u", + (unsigned long)ts.tv_sec, + (unsigned)ts.tv_nsec); + json_add_string(result, fieldname, timebuf); +} + +void json_add_timeiso(struct json_stream *result, + const char *fieldname, + struct timeabs *time) +{ + char iso8601_msec_fmt[sizeof("YYYY-mm-ddTHH:MM:SS.%03dZ")]; + char iso8601_s[sizeof("YYYY-mm-ddTHH:MM:SS.nnnZ")]; + + strftime(iso8601_msec_fmt, sizeof(iso8601_msec_fmt), + "%FT%T.%%03dZ", gmtime(&time->ts.tv_sec)); + snprintf(iso8601_s, sizeof(iso8601_s), + iso8601_msec_fmt, (int) time->ts.tv_nsec / 1000000); + + json_add_string(result, fieldname, iso8601_s); +} + + +void json_add_tok(struct json_stream *result, const char *fieldname, + const jsmntok_t *tok, const char *buffer) +{ + char *space; + assert(tok->type != JSMN_UNDEFINED); + + space = json_member_direct(result, fieldname, json_tok_full_len(tok)); + memcpy(space, json_tok_full(buffer, tok), json_tok_full_len(tok)); +} + +void json_add_errcode(struct json_stream *result, const char *fieldname, + errcode_t code) +{ + json_add_member(result, fieldname, false, "%"PRIerrcode, code); +} + +void json_add_invstring(struct json_stream *result, const char *invstring) +{ + if (strstarts(invstring, "lni")) + json_add_string(result, "bolt12", invstring); + else + json_add_string(result, "bolt11", invstring); +} + +void json_add_node_id(struct json_stream *response, + const char *fieldname, + const struct node_id *id) +{ + json_add_hex(response, fieldname, id->k, sizeof(id->k)); +} + +void json_add_channel_id(struct json_stream *response, + const char *fieldname, + const struct channel_id *cid) +{ + json_add_hex(response, fieldname, cid->id, sizeof(cid->id)); +} + +void json_add_pubkey(struct json_stream *response, + const char *fieldname, + const struct pubkey *key) +{ + u8 der[PUBKEY_CMPR_LEN]; + + pubkey_to_der(der, key); + json_add_hex(response, fieldname, der, sizeof(der)); +} + +void json_add_point32(struct json_stream *response, + const char *fieldname, + const struct point32 *key) +{ + u8 output[32]; + + secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, &key->pubkey); + json_add_hex(response, fieldname, output, sizeof(output)); +} + +void json_add_bip340sig(struct json_stream *response, + const char *fieldname, + const struct bip340sig *sig) +{ + json_add_hex(response, fieldname, sig->u8, sizeof(sig->u8)); +} + +void json_add_txid(struct json_stream *result, const char *fieldname, + const struct bitcoin_txid *txid) +{ + char hex[hex_str_size(sizeof(*txid))]; + + bitcoin_txid_to_hex(txid, hex, sizeof(hex)); + json_add_string(result, fieldname, hex); +} + +void json_add_outpoint(struct json_stream *result, const char *fieldname, + const struct bitcoin_outpoint *out) +{ + char hex[hex_str_size(sizeof(out->txid))]; + bitcoin_txid_to_hex(&out->txid, hex, sizeof(hex)); + json_add_member(result, fieldname, true, "%s:%d", hex, out->n); +} + +void json_add_short_channel_id(struct json_stream *response, + const char *fieldname, + const struct short_channel_id *scid) +{ + json_add_member(response, fieldname, true, "%dx%dx%d", + short_channel_id_blocknum(scid), + short_channel_id_txnum(scid), + short_channel_id_outnum(scid)); +} + +void json_add_address(struct json_stream *response, const char *fieldname, + const struct wireaddr *addr) +{ + json_object_start(response, fieldname); + if (addr->type == ADDR_TYPE_IPV4) { + char addrstr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, addr->addr, addrstr, INET_ADDRSTRLEN); + json_add_string(response, "type", "ipv4"); + json_add_string(response, "address", addrstr); + json_add_num(response, "port", addr->port); + } else if (addr->type == ADDR_TYPE_IPV6) { + char addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, addr->addr, addrstr, INET6_ADDRSTRLEN); + json_add_string(response, "type", "ipv6"); + json_add_string(response, "address", addrstr); + json_add_num(response, "port", addr->port); + } else if (addr->type == ADDR_TYPE_TOR_V2_REMOVED) { + json_add_string(response, "type", "torv2"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + } else if (addr->type == ADDR_TYPE_TOR_V3) { + json_add_string(response, "type", "torv3"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + } else if (addr->type == ADDR_TYPE_DNS) { + json_add_string(response, "type", "dns"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + } else if (addr->type == ADDR_TYPE_WEBSOCKET) { + json_add_string(response, "type", "websocket"); + json_add_num(response, "port", addr->port); + } + json_object_end(response); +} + +void json_add_address_internal(struct json_stream *response, + const char *fieldname, + const struct wireaddr_internal *addr) +{ + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + json_object_start(response, fieldname); + json_add_string(response, "type", "local socket"); + json_add_string(response, "socket", addr->u.sockname); + json_object_end(response); + return; + case ADDR_INTERNAL_ALLPROTO: + json_object_start(response, fieldname); + json_add_string(response, "type", "any protocol"); + json_add_num(response, "port", addr->u.port); + json_object_end(response); + return; + case ADDR_INTERNAL_AUTOTOR: + json_object_start(response, fieldname); + json_add_string(response, "type", "Tor generated address"); + json_add_address(response, "service", &addr->u.torservice.address); + json_object_end(response); + return; + case ADDR_INTERNAL_STATICTOR: + json_object_start(response, fieldname); + json_add_string(response, "type", "Tor from blob generated static address"); + json_add_address(response, "service", &addr->u.torservice.address); + json_object_end(response); + return; + case ADDR_INTERNAL_FORPROXY: + json_object_start(response, fieldname); + json_add_string(response, "type", "unresolved"); + json_add_string(response, "name", addr->u.unresolved.name); + json_add_num(response, "port", addr->u.unresolved.port); + json_object_end(response); + return; + case ADDR_INTERNAL_WIREADDR: + json_add_address(response, fieldname, &addr->u.wireaddr); + return; + } + abort(); +} + +void json_add_tx(struct json_stream *result, + const char *fieldname, + const struct bitcoin_tx *tx) +{ + json_add_hex_talarr(result, fieldname, linearize_tx(tmpctx, tx)); +} + +void json_add_psbt(struct json_stream *stream, + const char *fieldname, + const struct wally_psbt *psbt TAKES) +{ + const char *psbt_b64; + psbt_b64 = psbt_to_b64(NULL, psbt); + json_add_string(stream, fieldname, take(psbt_b64)); + if (taken(psbt)) + tal_free(psbt); +} + +void json_add_amount_msat_compat(struct json_stream *result, + struct amount_msat msat, + const char *rawfieldname, + const char *msatfieldname) +{ + if (deprecated_apis) + json_add_u64(result, rawfieldname, msat.millisatoshis); /* Raw: low-level helper */ + json_add_amount_msat_only(result, msatfieldname, msat); +} + +void json_add_amount_msat_only(struct json_stream *result, + const char *msatfieldname, + struct amount_msat msat) +{ + if (!deprecated_apis) + assert(strends(msatfieldname, "_msat")); + if (deprecated_apis) + json_add_string(result, msatfieldname, + type_to_string(tmpctx, struct amount_msat, &msat)); + else + json_add_u64(result, msatfieldname, msat.millisatoshis); /* Raw: low-level helper */ +} + +void json_add_amount_sat_compat(struct json_stream *result, + struct amount_sat sat, + const char *rawfieldname, + const char *msatfieldname) +{ + if (deprecated_apis) + json_add_u64(result, rawfieldname, sat.satoshis); /* Raw: low-level helper */ + json_add_amount_sat_msat(result, msatfieldname, sat); +} + +void json_add_amount_sat_msat(struct json_stream *result, + const char *msatfieldname, + struct amount_sat sat) +{ + struct amount_msat msat; + assert(strends(msatfieldname, "_msat")); + if (amount_sat_to_msat(&msat, sat)) + json_add_amount_msat_only(result, msatfieldname, msat); +} + +/* When I noticed that we were adding "XXXmsat" fields *not* ending in _msat */ +void json_add_amount_sats_deprecated(struct json_stream *result, + const char *fieldname, + const char *msatfieldname, + struct amount_sat sat) +{ + if (deprecated_apis) { + struct amount_msat msat; + assert(!strends(fieldname, "_msat")); + if (amount_sat_to_msat(&msat, sat)) + json_add_string(result, fieldname, + take(fmt_amount_msat(NULL, msat))); + } + json_add_amount_sat_msat(result, msatfieldname, sat); +} + +void json_add_sats(struct json_stream *result, + const char *fieldname, + struct amount_sat sat) +{ + json_add_string(result, fieldname, take(fmt_amount_sat(NULL, sat))); +} + +void json_add_secret(struct json_stream *response, const char *fieldname, + const struct secret *secret) +{ + json_add_hex(response, fieldname, secret, sizeof(struct secret)); +} + +void json_add_sha256(struct json_stream *result, const char *fieldname, + const struct sha256 *hash) +{ + json_add_hex(result, fieldname, hash, sizeof(*hash)); +} + +void json_add_preimage(struct json_stream *result, const char *fieldname, + const struct preimage *preimage) +{ + json_add_hex(result, fieldname, preimage, sizeof(*preimage)); +} + +void json_add_lease_rates(struct json_stream *result, + const struct lease_rates *rates) +{ + json_add_amount_sat_msat(result, "lease_fee_base_msat", + amount_sat(rates->lease_fee_base_sat)); + json_add_num(result, "lease_fee_basis", rates->lease_fee_basis); + json_add_num(result, "funding_weight", rates->funding_weight); + json_add_amount_msat_only(result, + "channel_fee_max_base_msat", + amount_msat(rates->channel_fee_max_base_msat)); + json_add_num(result, "channel_fee_max_proportional_thousandths", + rates->channel_fee_max_proportional_thousandths); +} + diff --git a/common/json_stream.h b/common/json_stream.h index 2c1dceee2..71bf82814 100644 --- a/common/json_stream.h +++ b/common/json_stream.h @@ -4,11 +4,36 @@ #ifndef LIGHTNING_COMMON_JSON_STREAM_H #define LIGHTNING_COMMON_JSON_STREAM_H #include "config.h" + +#define JSMN_STRICT 1 +# include + +#include #include +#include +#include +#include struct command; struct io_conn; struct log; +struct json_escape; +struct pubkey; +struct point32; +struct bip340sig; +struct secret; +struct node_id; +struct channel_id; +struct bitcoin_txid; +struct bitcoin_outpoint; +struct short_channel_id; +struct sha256; +struct preimage; +struct bitcoin_tx; +struct wally_psbt; +struct lease_rates; +struct wireaddr; +struct wireaddr_internal; struct json_stream { struct json_out *jout; @@ -146,4 +171,196 @@ struct io_plan *json_stream_output_(struct json_stream *js, void json_stream_double_cr(struct json_stream *js); void json_stream_flush(struct json_stream *js); +/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. Turns + * any non-printable chars into JSON escapes, but leaves existing escapes alone. + */ +void json_add_string(struct json_stream *result, const char *fieldname, const char *value); + +/* '"fieldname" : "value[:value_len]"' or '"value[:value_len]"' if + * fieldname is NULL. Turns any non-printable chars into JSON + * escapes, but leaves existing escapes alone. + */ +void json_add_stringn(struct json_stream *result, const char *fieldname, + const char *value TAKES, size_t value_len); + +/* '"fieldname" : "value"' or '"value"' if fieldname is NULL. String must + * already be JSON escaped as necessary. */ +void json_add_escaped_string(struct json_stream *result, + const char *fieldname, + const struct json_escape *esc TAKES); + +/* '"fieldname" : literal' or 'literal' if fieldname is NULL*/ +void json_add_literal(struct json_stream *result, const char *fieldname, + const char *literal, int len); +/* '"fieldname" : value' or 'value' if fieldname is NULL */ +void json_add_num(struct json_stream *result, const char *fieldname, + unsigned int value); +/* '"fieldname" : value' or 'value' if fieldname is NULL */ +void json_add_u64(struct json_stream *result, const char *fieldname, + uint64_t value); +/* '"fieldname" : value' or 'value' if fieldname is NULL */ +void json_add_s64(struct json_stream *result, const char *fieldname, + int64_t value); +/* '"fieldname" : value' or 'value' if fieldname is NULL */ +void json_add_u32(struct json_stream *result, const char *fieldname, + uint32_t value); +/* '"fieldname" : value' or 'value' if fieldname is NULL */ +void json_add_s32(struct json_stream *result, const char *fieldname, + int32_t value); +/* '"fieldname" : true|false' or 'true|false' if fieldname is NULL */ +void json_add_bool(struct json_stream *result, const char *fieldname, + bool value); + +/* '"fieldname" : null' or 'null' if fieldname is NULL */ +void json_add_null(struct json_stream *stream, const char *fieldname); + +/* '"fieldname" : "0189abcdef..."' or "0189abcdef..." if fieldname is NULL */ +void json_add_hex(struct json_stream *result, const char *fieldname, + const void *data, size_t len); +/* '"fieldname" : "0189abcdef..."' or "0189abcdef..." if fieldname is NULL */ +void json_add_hex_talarr(struct json_stream *result, + const char *fieldname, + const tal_t *data); + +void json_add_timeabs(struct json_stream *result, const char *fieldname, + struct timeabs t); + +/* used in log.c and notification.c*/ +void json_add_time(struct json_stream *result, const char *fieldname, + struct timespec ts); + +/* Add ISO_8601 timestamp string, i.e. "2019-09-07T15:50+01:00" */ +void json_add_timeiso(struct json_stream *result, + const char *fieldname, + struct timeabs *time); + +/* Add any json token */ +void json_add_tok(struct json_stream *result, const char *fieldname, + const jsmntok_t *tok, const char *buffer); + +/* Add an error code */ +void json_add_errcode(struct json_stream *result, const char *fieldname, + errcode_t code); + +/* Add "bolt11" or "bolt12" field, depending on invstring. */ +void json_add_invstring(struct json_stream *result, const char *invstring); + +/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ +void json_add_pubkey(struct json_stream *response, + const char *fieldname, + const struct pubkey *key); + +/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ +void json_add_point32(struct json_stream *response, + const char *fieldname, + const struct point32 *key); + +/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ +void json_add_bip340sig(struct json_stream *response, + const char *fieldname, + const struct bip340sig *sig); + +/* '"fieldname" : "89abcdef..."' or "89abcdef..." if fieldname is NULL */ +void json_add_secret(struct json_stream *response, + const char *fieldname, + const struct secret *secret); + +/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ +void json_add_node_id(struct json_stream *response, + const char *fieldname, + const struct node_id *id); + +/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */ +void json_add_channel_id(struct json_stream *response, + const char *fieldname, + const struct channel_id *cid); + +/* '"fieldname" : ' or "" if fieldname is NULL */ +void json_add_txid(struct json_stream *result, const char *fieldname, + const struct bitcoin_txid *txid); + +/* '"fieldname" : "txid:n" */ +void json_add_outpoint(struct json_stream *result, const char *fieldname, + const struct bitcoin_outpoint *out); + +/* '"fieldname" : "1234:5:6"' */ +void json_add_short_channel_id(struct json_stream *response, + const char *fieldname, + const struct short_channel_id *id); + +/* JSON serialize a network address for a node */ +void json_add_address(struct json_stream *response, const char *fieldname, + const struct wireaddr *addr); + +/* JSON serialize a network address for a node. */ +void json_add_address_internal(struct json_stream *response, + const char *fieldname, + const struct wireaddr_internal *addr); + +/* Adds both a 'raw' number field and an 'amount_msat' field */ +void json_add_amount_msat_compat(struct json_stream *result, + struct amount_msat msat, + const char *rawfieldname, + const char *msatfieldname) + NO_NULL_ARGS; + +/* Adds both a 'raw' number field and an 'amount_msat' field */ +void json_add_amount_sat_compat(struct json_stream *result, + struct amount_sat sat, + const char *rawfieldname, + const char *msatfieldname) + NO_NULL_ARGS; + +/* Adds an 'msat' field */ +void json_add_amount_msat_only(struct json_stream *result, + const char *msatfieldname, + struct amount_msat msat) + NO_NULL_ARGS; + +/* Adds an 'msat' field */ +void json_add_amount_sat_only(struct json_stream *result, + const char *msatfieldname, + struct amount_sat sat) + NO_NULL_ARGS; + +/* Adds an 'msat' field */ +void json_add_amount_sat_msat(struct json_stream *result, + const char *msatfieldname, + struct amount_sat sat) + NO_NULL_ARGS; + +/* Adds an 'msat' field, and an older deprecated field. */ +void json_add_amount_sats_deprecated(struct json_stream *result, + const char *fieldname, + const char *msatfieldname, + struct amount_sat sat) + NO_NULL_ARGS; + +/* This is used to create requests, *never* for output (output is always + * msat!) */ +void json_add_sats(struct json_stream *result, + const char *fieldname, + struct amount_sat sat) + NO_NULL_ARGS; + +void json_add_sha256(struct json_stream *result, const char *fieldname, + const struct sha256 *hash); + +void json_add_preimage(struct json_stream *result, const char *fieldname, + const struct preimage *preimage); + +/* '"fieldname" : "010000000001..."' or "010000000001..." if fieldname is NULL */ +void json_add_tx(struct json_stream *result, + const char *fieldname, + const struct bitcoin_tx *tx); + +/* '"fieldname" : "cHNidP8BAJoCAAAAAljo..." or "cHNidP8BAJoCAAAAAljo..." if fieldname is NULL */ +void json_add_psbt(struct json_stream *stream, + const char *fieldname, + const struct wally_psbt *psbt); + +/* Add fields from the lease_rates to a json stream. + * Note that field names are set */ +void json_add_lease_rates(struct json_stream *result, + const struct lease_rates *rates); #endif /* LIGHTNING_COMMON_JSON_STREAM_H */ diff --git a/common/param.c b/common/param.c deleted file mode 100644 index c591baf4f..000000000 --- a/common/param.c +++ /dev/null @@ -1,369 +0,0 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include - -struct param { - const char *name; - bool is_set; - enum param_style style; - param_cbx cbx; - void *arg; -}; - -static bool param_add(struct param **params, - const char *name, - enum param_style style, - param_cbx cbx, void *arg) -{ -#if DEVELOPER - if (!(name && cbx && arg)) - return false; -#endif - struct param last; - - last.is_set = false; - last.name = name; - last.style = style; - last.cbx = cbx; - last.arg = arg; - - tal_arr_expand(params, last); - return true; -} - -/* FIXME: To support the deprecated p_req_dup_ok */ -static bool is_required(enum param_style style) -{ - return style == PARAM_REQUIRED || style == PARAM_REQUIRED_ALLOW_DUPS; -} - -static struct command_result *make_callback(struct command *cmd, - struct param *def, - const char *buffer, - const jsmntok_t *tok) -{ - /* If it had a default, free that now to avoid leak */ - if (def->style == PARAM_OPTIONAL_WITH_DEFAULT && !def->is_set) - tal_free(*(void **)def->arg); - - def->is_set = true; - - return def->cbx(cmd, def->name, buffer, tok, def->arg); -} - -static struct command_result *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 && is_required(first->style)) { - if (!first->is_set) { - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "missing required parameter: %s", - first->name); - } - first++; - } - return NULL; -} - -static struct command_result *parse_by_position(struct command *cmd, - struct param *params, - const char *buffer, - const jsmntok_t tokens[], - bool allow_extra) -{ - struct command_result *res; - const jsmntok_t *tok; - size_t i; - - json_for_each_arr(i, tok, tokens) { - /* check for unexpected trailing params */ - if (i == tal_count(params)) { - if (!allow_extra) { - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "too many parameters:" - " got %u, expected %zu", - tokens->size, - tal_count(params)); - } - break; - } - - if (!json_tok_is_null(buffer, tok)) { - res = make_callback(cmd, params+i, buffer, tok); - if (res) - return res; - } - } - - 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) { - size_t arglen = strcspn(first->name, "|"); - if (memeq(first->name, arglen, start, n)) - return first; - if (deprecated_apis - && first->name[arglen] - && memeq(first->name + arglen + 1, - strlen(first->name + arglen + 1), - start, n)) - return first; - first++; - } - return NULL; -} - -static struct command_result *parse_by_name(struct command *cmd, - struct param *params, - const char *buffer, - const jsmntok_t tokens[], - bool allow_extra) -{ - size_t i; - const jsmntok_t *t; - - json_for_each_obj(i, t, tokens) { - struct param *p = find_param(params, buffer + t->start, - t->end - t->start); - if (!p) { - if (!allow_extra) { - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "unknown parameter: %.*s, this may be caused by a failure to autodetect key=value-style parameters. Please try using the -k flag and explicit key=value pairs of parameters.", - t->end - t->start, - buffer + t->start); - } - } else { - struct command_result *res; - - if (p->is_set) { - if (p->style == PARAM_REQUIRED_ALLOW_DUPS) - continue; - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "duplicate json names: %s", - p->name); - } - - res = make_callback(cmd, p, buffer, t + 1); - if (res) - return res; - } - } - 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 (!is_required(a->style) && is_required(b->style)) - 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_talarr(params, struct param, params); - - /* 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++) { - /* Don't print |deprecated part! */ - int len = strcspn(params[i].name, "|"); - if (i != 0) - tal_append_fmt(&usage, " "); - if (is_required(params[i].style)) - tal_append_fmt(&usage, "%.*s", len, params[i].name); - else - tal_append_fmt(&usage, "[%.*s]", len, params[i].name); - } - return usage; -} - -static struct command_result *param_arr(struct command *cmd, const char *buffer, - const jsmntok_t tokens[], - struct param *params, - bool allow_extra) -{ -#if DEVELOPER - if (!check_params(params)) { - return command_fail(cmd, PARAM_DEV_ERROR, - "developer error: check_params"); - } -#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); - - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Expected array or object for params"); -} - -const char *param_subcommand(struct command *cmd, const char *buffer, - const jsmntok_t tokens[], - const char *name, ...) -{ - va_list ap; - struct param *params = tal_arr(cmd, struct param, 0); - const char *arg, **names = tal_arr(tmpctx, const char *, 1); - const char *subcmd; - - param_add(¶ms, "subcommand", PARAM_REQUIRED, (void *)param_string, &subcmd); - names[0] = name; - va_start(ap, name); - while ((arg = va_arg(ap, const char *)) != NULL) - tal_arr_expand(&names, arg); - va_end(ap); - - if (command_usage_only(cmd)) { - char *usage = tal_strdup(cmd, "subcommand"); - for (size_t i = 0; i < tal_count(names); i++) - tal_append_fmt(&usage, "%c%s", - i == 0 ? '=' : '|', names[i]); - command_set_usage(cmd, usage); - return NULL; - } - - /* Check it's valid */ - if (param_arr(cmd, buffer, tokens, params, true) != NULL) { - return NULL; - } - - /* Check it's one of the known ones. */ - for (size_t i = 0; i < tal_count(names); i++) - if (streq(subcmd, names[i])) - return subcmd; - - /* We really do ignore this. */ - struct command_result *ignore; - ignore = command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Unknown subcommand '%s'", subcmd); - assert(ignore); - return NULL; -} - -bool param(struct command *cmd, const char *buffer, - const jsmntok_t tokens[], ...) -{ - struct param *params = tal_arr(tmpctx, 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) { - enum param_style style = va_arg(ap, enum param_style); - 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, style, cbx, arg)) { - /* We really do ignore this return! */ - struct command_result *ignore; - ignore = command_fail(cmd, PARAM_DEV_ERROR, - "developer error: param_add %s", name); - assert(ignore); - 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) == NULL - && !command_check_only(cmd); -} diff --git a/common/param.h b/common/param.h deleted file mode 100644 index 6db4e80dd..000000000 --- a/common/param.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef LIGHTNING_COMMON_PARAM_H -#define LIGHTNING_COMMON_PARAM_H -#include "config.h" -#include - -/*~ Greetings adventurer! - * - * Do you want to automatically validate json input and unmarshal 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("amount_msat|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 - * common/json_tok.c. Use them directly or feel free to write your own. - */ -struct command; - -/* A dummy type returned by command_ functions, to ensure you return them - * immediately */ -struct command_result; - -/* - * 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[], ...) LAST_ARG_NULL; - -/* - * The callback signature. - * - * Callbacks must return NULL on success. On failure they - * must return command_fail(...). - */ -typedef struct command_result *(*param_cbx)(struct command *cmd, - const char *name, - const char *buffer, - const jsmntok_t *tok, - void **arg); - -/** - * Parse the first json value. - * - * name...: NULL-terminated array of valid values. - * - * Returns subcommand: if it returns NULL if you should return - * command_param_failed() immediately. - */ -const char *param_subcommand(struct command *cmd, const char *buffer, - const jsmntok_t tokens[], - const char *name, ...) LAST_ARG_NULL; - -enum param_style { - PARAM_REQUIRED, - PARAM_REQUIRED_ALLOW_DUPS, - PARAM_OPTIONAL, - PARAM_OPTIONAL_WITH_DEFAULT, -}; - -/* - * Add a required parameter. - * name can be | if it's been renamed. - */ -#define p_req(name, cbx, arg) \ - name"", \ - PARAM_REQUIRED, \ - (param_cbx)(cbx), \ - (arg) + 0*sizeof((cbx)((struct command *)NULL, \ - (const char *)NULL, \ - (const char *)NULL, \ - (const jsmntok_t *)NULL, \ - (arg)) == (struct command_result *)NULL) - -/* - * Add an optional parameter. *arg is set to NULL if it isn't found. - * name can be | if it's been renamed. - */ -#define p_opt(name, cbx, arg) \ - name"", \ - PARAM_OPTIONAL, \ - (param_cbx)(cbx), \ - ({ *arg = NULL; \ - (arg) + 0*sizeof((cbx)((struct command *)NULL, \ - (const char *)NULL, \ - (const char *)NULL, \ - (const jsmntok_t *)NULL, \ - (arg)) == (struct command_result *)NULL); }) - -/* - * Add an required parameter, like p_req, but ignore duplicates. - */ -#define p_req_dup_ok(name, cbx, arg) \ - name"", \ - PARAM_REQUIRED_ALLOW_DUPS, \ - (param_cbx)(cbx), \ - ({ *arg = NULL; \ - (arg) + 0*sizeof((cbx)((struct command *)NULL, \ - (const char *)NULL, \ - (const char *)NULL, \ - (const jsmntok_t *)NULL, \ - (arg)) == (struct command_result *)NULL); }) - -/* - * Add an optional parameter. *arg is set to @def if it isn't found. - * name can be | if it's been renamed. - */ -#define p_opt_def(name, cbx, arg, def) \ - name"", \ - PARAM_OPTIONAL_WITH_DEFAULT, \ - (param_cbx)(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)) == (struct command_result *)NULL); }) - -/* Special flag for 'check' which allows any parameters. */ -#define p_opt_any() "", PARAM_OPTIONAL, NULL, NULL -#endif /* LIGHTNING_COMMON_PARAM_H */ diff --git a/common/test/Makefile b/common/test/Makefile index 309110505..3304f2f5f 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -21,8 +21,8 @@ ALL_TEST_PROGRAMS += $(COMMON_TEST_PROGRAMS) # Sphinx test wants to decode TLVs. common/test/run-sphinx: wire/onion$(EXP)_wiregen.o wire/towire.o wire/fromwire.o common/test/run-blindedpath_enctlv common/test/run-blindedpath_onion: common/base32.o common/wireaddr.o wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o -common/test/run-route_blinding_test: wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/json.o common/json_helpers.o common/coin_mvt.o -common/test/run-route_blinding_override_test: common/base32.o common/wireaddr.o wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/json.o common/json_helpers.o common/coin_mvt.o +common/test/run-route_blinding_test: wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o +common/test/run-route_blinding_override_test: common/base32.o common/wireaddr.o wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o common/test/run-param \ common/test/run-json: \ @@ -31,7 +31,6 @@ common/test/run-json: \ common/bigsize.o \ common/channel_id.o \ common/coin_mvt.o \ - common/json.o \ common/json_stream.o \ common/lease_rates.o \ common/node_id.o \ diff --git a/common/test/run-bigsize.c b/common/test/run-bigsize.c index d972f17e2..46590bdb7 100644 --- a/common/test/run-bigsize.c +++ b/common/test/run-bigsize.c @@ -2,7 +2,8 @@ #include #include #include -#include +#include +#include #include static const char *reason; @@ -74,16 +75,18 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } +/* Generated stub for mvt_tag_str */ +const char *mvt_tag_str(enum mvt_tag tag UNNEEDED) +{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); } +/* Generated stub for node_id_from_hexstr */ +bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } +/* Generated stub for parse_amount_msat */ +bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } +/* Generated stub for parse_amount_sat */ +bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 42173ebfa..348af56bd 100644 --- a/common/test/run-bolt12_decode.c +++ b/common/test/run-bolt12_decode.c @@ -2,7 +2,8 @@ #include "../bolt12.c" #include "../bech32_util.c" #include "../bech32.c" -#include "../json.c" +#include "../json_parse.c" +#include "../json_parse_simple.c" #include #include #include @@ -89,19 +90,21 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for merkle_tlv */ void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle UNNEEDED) { fprintf(stderr, "merkle_tlv called!\n"); abort(); } +/* Generated stub for mvt_tag_str */ +const char *mvt_tag_str(enum mvt_tag tag UNNEEDED) +{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); } +/* Generated stub for node_id_from_hexstr */ +bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } +/* Generated stub for parse_amount_msat */ +bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } +/* Generated stub for parse_amount_sat */ +bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } /* Generated stub for sighash_from_merkle */ void sighash_from_merkle(const char *messagename UNNEEDED, const char *fieldname UNNEEDED, diff --git a/common/test/run-bolt12_merkle-json.c b/common/test/run-bolt12_merkle-json.c index ef594f2c2..495796da4 100644 --- a/common/test/run-bolt12_merkle-json.c +++ b/common/test/run-bolt12_merkle-json.c @@ -2,7 +2,7 @@ #include "../amount.c" #include "../bigsize.c" #include "../bolt12_merkle.c" -#include "../json.c" +#include "../json_parse.c" #include "../../wire/fromwire.c" #include "../../wire/tlvstream.c" #if EXPERIMENTAL_FEATURES @@ -28,16 +28,47 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n /* Generated stub for fromwire_onionmsg_path */ struct onionmsg_path *fromwire_onionmsg_path(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED) { fprintf(stderr, "fromwire_onionmsg_path called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } +/* Generated stub for json_get_arr */ +const jsmntok_t *json_get_arr(const jsmntok_t tok[] UNNEEDED, size_t index UNNEEDED) +{ fprintf(stderr, "json_get_arr called!\n"); abort(); } +/* Generated stub for json_get_member */ +const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED, + const char *label UNNEEDED) +{ fprintf(stderr, "json_get_member called!\n"); abort(); } +/* Generated stub for json_get_membern */ +const jsmntok_t *json_get_membern(const char *buffer UNNEEDED, + const jsmntok_t tok[] UNNEEDED, + const char *label UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "json_get_membern called!\n"); abort(); } +/* Generated stub for json_next */ +const jsmntok_t *json_next(const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_next called!\n"); abort(); } +/* Generated stub for json_strdup */ +char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_strdup called!\n"); abort(); } +/* Generated stub for json_to_u32 */ +bool json_to_u32(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint32_t *num UNNEEDED) +{ fprintf(stderr, "json_to_u32 called!\n"); abort(); } +/* Generated stub for json_to_u64 */ +bool json_to_u64(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint64_t *num UNNEEDED) +{ fprintf(stderr, "json_to_u64 called!\n"); abort(); } +/* Generated stub for json_tok_full */ +const char *json_tok_full(const char *buffer UNNEEDED, const jsmntok_t *t UNNEEDED) +{ fprintf(stderr, "json_tok_full called!\n"); abort(); } +/* Generated stub for json_tok_full_len */ +int json_tok_full_len(const jsmntok_t *t UNNEEDED) +{ fprintf(stderr, "json_tok_full_len called!\n"); abort(); } +/* Generated stub for json_tok_streq */ +bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const char *str UNNEEDED) +{ fprintf(stderr, "json_tok_streq called!\n"); abort(); } +/* Generated stub for mvt_tag_str */ +const char *mvt_tag_str(enum mvt_tag tag UNNEEDED) +{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); } +/* Generated stub for node_id_from_hexstr */ +bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-bolt12_period.c b/common/test/run-bolt12_period.c index 55e6db907..1b8bd553f 100644 --- a/common/test/run-bolt12_period.c +++ b/common/test/run-bolt12_period.c @@ -1,6 +1,7 @@ #include "config.h" #include "../bolt12.c" -#include "../json.c" +#include "../json_parse.c" +#include "../json_parse_simple.c" #include #include #include @@ -92,19 +93,21 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for merkle_tlv */ void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle UNNEEDED) { fprintf(stderr, "merkle_tlv called!\n"); abort(); } +/* Generated stub for mvt_tag_str */ +const char *mvt_tag_str(enum mvt_tag tag UNNEEDED) +{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); } +/* Generated stub for node_id_from_hexstr */ +bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } +/* Generated stub for parse_amount_msat */ +bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } +/* Generated stub for parse_amount_sat */ +bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } /* Generated stub for sighash_from_merkle */ void sighash_from_merkle(const char *messagename UNNEEDED, const char *fieldname UNNEEDED, diff --git a/common/test/run-json.c b/common/test/run-json.c index db437a5e7..d283fbcd5 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -1,5 +1,6 @@ #include "config.h" -#include "../json_helpers.c" +#include "../json_parse.c" +#include "../json_parse_simple.c" #include #include #include diff --git a/common/test/run-json_remove.c b/common/test/run-json_remove.c index f821b95f4..e859dbcb4 100644 --- a/common/test/run-json_remove.c +++ b/common/test/run-json_remove.c @@ -1,7 +1,9 @@ #include "config.h" #include -#include +#include +#include #include +#include #include /* AUTOGENERATED MOCKS START */ @@ -36,6 +38,22 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for command_check_only */ +bool command_check_only(const struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_check_only called!\n"); abort(); } +/* Generated stub for command_fail */ +struct command_result *command_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED, + const char *fmt UNNEEDED, ...) + +{ fprintf(stderr, "command_fail called!\n"); abort(); } +/* Generated stub for command_set_usage */ +void command_set_usage(struct command *cmd UNNEEDED, const char *usage UNNEEDED) +{ fprintf(stderr, "command_set_usage called!\n"); abort(); } +/* Generated stub for command_usage_only */ +bool command_usage_only(const struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_usage_only called!\n"); abort(); } +/* Generated stub for deprecated_apis */ +bool deprecated_apis; /* Generated stub for fromwire */ const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) { fprintf(stderr, "fromwire called!\n"); abort(); } @@ -68,16 +86,75 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } +/* Generated stub for json_scan */ +const char *json_scan(const tal_t *ctx UNNEEDED, + const char *buffer UNNEEDED, + const jsmntok_t *tok UNNEEDED, + const char *guide UNNEEDED, + ...) +{ fprintf(stderr, "json_scan called!\n"); abort(); } +/* Generated stub for json_to_channel_id */ +bool json_to_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct channel_id *cid UNNEEDED) +{ fprintf(stderr, "json_to_channel_id called!\n"); abort(); } +/* Generated stub for json_to_millionths */ +bool json_to_millionths(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + u64 *millionths UNNEEDED) +{ fprintf(stderr, "json_to_millionths called!\n"); abort(); } +/* Generated stub for json_to_msat */ +bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct amount_msat *msat UNNEEDED) +{ fprintf(stderr, "json_to_msat called!\n"); abort(); } +/* Generated stub for json_to_node_id */ +bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct node_id *id UNNEEDED) +{ fprintf(stderr, "json_to_node_id called!\n"); abort(); } +/* Generated stub for json_to_number */ +bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + unsigned int *num UNNEEDED) +{ fprintf(stderr, "json_to_number called!\n"); abort(); } +/* Generated stub for json_to_outpoint */ +bool json_to_outpoint(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct bitcoin_outpoint *op UNNEEDED) +{ fprintf(stderr, "json_to_outpoint called!\n"); abort(); } +/* Generated stub for json_to_pubkey */ +bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); } +/* Generated stub for json_to_short_channel_id */ +bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } +/* Generated stub for json_to_txid */ +bool json_to_txid(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct bitcoin_txid *txid UNNEEDED) +{ fprintf(stderr, "json_to_txid called!\n"); abort(); } +/* Generated stub for json_to_u16 */ +bool json_to_u16(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint16_t *num UNNEEDED) +{ fprintf(stderr, "json_to_u16 called!\n"); abort(); } +/* Generated stub for json_tok_bin_from_hex */ +u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); } +/* Generated stub for lease_rates_fromhex */ +struct lease_rates *lease_rates_fromhex(const tal_t *ctx UNNEEDED, + const char *hexdata UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "lease_rates_fromhex called!\n"); abort(); } +/* Generated stub for parse_amount_msat */ +bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } +/* Generated stub for parse_amount_sat */ +bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } +/* Generated stub for segwit_addr_decode */ +int segwit_addr_decode( + int* ver UNNEEDED, + uint8_t* prog UNNEEDED, + size_t* prog_len UNNEEDED, + const char* hrp UNNEEDED, + const char* addr +) +{ fprintf(stderr, "segwit_addr_decode called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-json_scan.c b/common/test/run-json_scan.c index 230a5348d..7dfdc8247 100644 --- a/common/test/run-json_scan.c +++ b/common/test/run-json_scan.c @@ -1,5 +1,6 @@ #include "config.h" -#include "../json.c" +#include "../json_parse.c" +#include "../json_parse_simple.c" #include #include #include @@ -68,16 +69,18 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } +/* Generated stub for mvt_tag_str */ +const char *mvt_tag_str(enum mvt_tag tag UNNEEDED) +{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); } +/* Generated stub for node_id_from_hexstr */ +bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } +/* Generated stub for parse_amount_msat */ +bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } +/* Generated stub for parse_amount_sat */ +bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) +{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-param.c b/common/test/run-param.c index c3611cfb5..078708649 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -1,6 +1,7 @@ #include "config.h" -#include "../json_tok.c" -#include "../param.c" +#include "../json_parse.c" +#include "../json_parse_simple.c" +#include "../json_param.c" #include #include #include @@ -42,34 +43,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for json_to_channel_id */ -bool json_to_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct channel_id *cid UNNEEDED) -{ fprintf(stderr, "json_to_channel_id called!\n"); abort(); } -/* Generated stub for json_to_msat */ -bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct amount_msat *msat UNNEEDED) -{ fprintf(stderr, "json_to_msat called!\n"); abort(); } -/* Generated stub for json_to_node_id */ -bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct node_id *id UNNEEDED) -{ fprintf(stderr, "json_to_node_id called!\n"); abort(); } -/* Generated stub for json_to_outpoint */ -bool json_to_outpoint(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct bitcoin_outpoint *op UNNEEDED) -{ fprintf(stderr, "json_to_outpoint called!\n"); abort(); } -/* Generated stub for json_to_pubkey */ -bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct pubkey *pubkey UNNEEDED) -{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); } -/* Generated stub for json_to_short_channel_id */ -bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct short_channel_id *scid UNNEEDED) -{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } -/* Generated stub for json_to_txid */ -bool json_to_txid(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - struct bitcoin_txid *txid UNNEEDED) -{ fprintf(stderr, "json_to_txid called!\n"); abort(); } /* Generated stub for segwit_addr_decode */ int segwit_addr_decode( int* ver UNNEEDED, diff --git a/common/test/run-route_blinding_override_test.c b/common/test/run-route_blinding_override_test.c index 4fbfd01d8..4692b73d3 100644 --- a/common/test/run-route_blinding_override_test.c +++ b/common/test/run-route_blinding_override_test.c @@ -7,8 +7,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -21,9 +20,6 @@ bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) /* Generated stub for amount_asset_to_sat */ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) { fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } -/* Generated stub for amount_msat */ -struct amount_msat amount_msat(u64 millisatoshis UNNEEDED) -{ fprintf(stderr, "amount_msat called!\n"); abort(); } /* Generated stub for amount_sat */ struct amount_sat amount_sat(u64 satoshis UNNEEDED) { fprintf(stderr, "amount_sat called!\n"); abort(); } @@ -53,14 +49,6 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; -/* Generated stub for fmt_amount_msat */ -const char *fmt_amount_msat(const tal_t *ctx UNNEEDED, struct amount_msat msat UNNEEDED) -{ fprintf(stderr, "fmt_amount_msat called!\n"); abort(); } -/* Generated stub for fmt_amount_sat */ -const char *fmt_amount_sat(const tal_t *ctx UNNEEDED, struct amount_sat sat UNNEEDED) -{ fprintf(stderr, "fmt_amount_sat called!\n"); abort(); } /* Generated stub for fromwire_amount_msat */ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); } @@ -74,31 +62,34 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } -/* Generated stub for node_id_from_hexstr */ -bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) -{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } -/* Generated stub for parse_amount_msat */ -bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) -{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } -/* Generated stub for parse_amount_sat */ -bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) -{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } +/* Generated stub for json_get_member */ +const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED, + const char *label UNNEEDED) +{ fprintf(stderr, "json_get_member called!\n"); abort(); } +/* Generated stub for json_next */ +const jsmntok_t *json_next(const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_next called!\n"); abort(); } +/* Generated stub for json_to_pubkey */ +bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); } +/* Generated stub for json_to_secret */ +bool json_to_secret(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct secret *dest UNNEEDED) +{ fprintf(stderr, "json_to_secret called!\n"); abort(); } +/* Generated stub for json_to_short_channel_id */ +bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } +/* Generated stub for json_tok_bin_from_hex */ +u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); } +/* Generated stub for json_tok_startswith */ +bool json_tok_startswith(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + const char *prefix UNNEEDED) +{ fprintf(stderr, "json_tok_startswith called!\n"); abort(); } +/* Generated stub for json_tok_streq */ +bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const char *str UNNEEDED) +{ fprintf(stderr, "json_tok_streq called!\n"); abort(); } /* Generated stub for towire_amount_msat */ void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED) { fprintf(stderr, "towire_amount_msat called!\n"); abort(); } diff --git a/common/test/run-route_blinding_test.c b/common/test/run-route_blinding_test.c index 82c0b7f2b..a67c805c7 100644 --- a/common/test/run-route_blinding_test.c +++ b/common/test/run-route_blinding_test.c @@ -7,8 +7,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -21,9 +20,6 @@ bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) /* Generated stub for amount_asset_to_sat */ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) { fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } -/* Generated stub for amount_msat */ -struct amount_msat amount_msat(u64 millisatoshis UNNEEDED) -{ fprintf(stderr, "amount_msat called!\n"); abort(); } /* Generated stub for amount_sat */ struct amount_sat amount_sat(u64 satoshis UNNEEDED) { fprintf(stderr, "amount_sat called!\n"); abort(); } @@ -53,17 +49,6 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; -/* Generated stub for fmt_amount_msat */ -const char *fmt_amount_msat(const tal_t *ctx UNNEEDED, struct amount_msat msat UNNEEDED) -{ fprintf(stderr, "fmt_amount_msat called!\n"); abort(); } -/* Generated stub for fmt_amount_sat */ -const char *fmt_amount_sat(const tal_t *ctx UNNEEDED, struct amount_sat sat UNNEEDED) -{ fprintf(stderr, "fmt_amount_sat 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 fromwire_amount_msat */ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); } @@ -77,31 +62,34 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } -/* Generated stub for node_id_from_hexstr */ -bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) -{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } -/* Generated stub for parse_amount_msat */ -bool parse_amount_msat(struct amount_msat *msat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) -{ fprintf(stderr, "parse_amount_msat called!\n"); abort(); } -/* Generated stub for parse_amount_sat */ -bool parse_amount_sat(struct amount_sat *sat UNNEEDED, const char *s UNNEEDED, size_t slen UNNEEDED) -{ fprintf(stderr, "parse_amount_sat called!\n"); abort(); } +/* Generated stub for json_get_member */ +const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED, + const char *label UNNEEDED) +{ fprintf(stderr, "json_get_member called!\n"); abort(); } +/* Generated stub for json_next */ +const jsmntok_t *json_next(const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_next called!\n"); abort(); } +/* Generated stub for json_to_pubkey */ +bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); } +/* Generated stub for json_to_secret */ +bool json_to_secret(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct secret *dest UNNEEDED) +{ fprintf(stderr, "json_to_secret called!\n"); abort(); } +/* Generated stub for json_to_short_channel_id */ +bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } +/* Generated stub for json_tok_bin_from_hex */ +u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); } +/* Generated stub for json_tok_startswith */ +bool json_tok_startswith(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + const char *prefix UNNEEDED) +{ fprintf(stderr, "json_tok_startswith called!\n"); abort(); } +/* Generated stub for json_tok_streq */ +bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const char *str UNNEEDED) +{ fprintf(stderr, "json_tok_streq called!\n"); abort(); } /* Generated stub for towire_amount_msat */ void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED) { fprintf(stderr, "towire_amount_msat called!\n"); abort(); } diff --git a/devtools/Makefile b/devtools/Makefile index fd3f66a37..98fd57e6c 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -29,14 +29,13 @@ DEVTOOLS_COMMON_OBJS := \ common/hash_u5.o \ common/hmac.o \ common/htlc_state.o \ + common/json_parse.o \ + common/json_parse_simple.o \ common/memleak.o \ common/node_id.o \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ - common/json.o \ - common/json_helpers.o \ - common/json_stream.o \ common/setup.o \ common/type_to_string.o \ common/utils.o \ diff --git a/devtools/onion.c b/devtools/onion.c index 82e5129cb..0acbbf498 100644 --- a/devtools/onion.c +++ b/devtools/onion.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/gossipd/test/Makefile b/gossipd/test/Makefile index fe39a0bbb..21ef60425 100644 --- a/gossipd/test/Makefile +++ b/gossipd/test/Makefile @@ -17,8 +17,6 @@ GOSSIPD_TEST_COMMON_OBJS := \ common/features.o \ common/hmac.o \ common/node_id.o \ - common/json.o \ - common/json_helpers.o \ common/lease_rates.o \ common/onion.o \ common/pseudorand.o \ @@ -46,6 +44,10 @@ gossipd/test/run-onion_message: \ common/onion.o \ common/sphinx.o \ +# JSON needed for this test +gossipd/test/run-extended-info: \ + common/json_parse.o \ + common/json_parse_simple.o $(GOSSIPD_TEST_PROGRAMS): $(GOSSIPD_TEST_COMMON_OBJS) $(BITCOIN_OBJS) diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index fb810dd46..d095f22b4 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -59,8 +59,6 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED, const struct half_chan *hc UNNEEDED, const u8 *cupdate UNNEEDED) { fprintf(stderr, "cupdate_different called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -94,22 +92,6 @@ void gossip_store_mark_channel_deleted(struct gossip_store *gs UNNEEDED, struct gossip_store *gossip_store_new(struct routing_state *rstate UNNEEDED, struct list_head *peers UNNEEDED) { fprintf(stderr, "gossip_store_new called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for memleak_add_helper_ */ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, const tal_t *)){ } diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index 0a53fe4b5..b7245bee3 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -27,8 +27,6 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, /* Generated stub for daemon_conn_send */ void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "daemon_conn_send called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -64,22 +62,6 @@ u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *updat u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, struct peer *peer UNNEEDED, bool *was_unknown UNNEEDED) { fprintf(stderr, "handle_node_announcement called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index f02f52d9d..0420958ed 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -45,8 +45,6 @@ bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED, /* Generated stub for decode_short_ids */ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED) { fprintf(stderr, "decode_short_ids called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -90,22 +88,6 @@ u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *updat u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, struct peer *peer UNNEEDED, bool *was_unknown UNNEEDED) { fprintf(stderr, "handle_node_announcement called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index 142ba69cd..d69b852f7 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -45,8 +45,6 @@ bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED, /* Generated stub for decode_short_ids */ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED) { fprintf(stderr, "decode_short_ids called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -67,22 +65,6 @@ const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, struct gossip_store *gs UNNEEDED, u64 offset UNNEEDED) { fprintf(stderr, "gossip_store_get called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index 21255cad1..8eeb85107 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -26,27 +26,9 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, const struct sha256 *h UNNEEDED, struct pubkey *next UNNEEDED) { fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for new_onionreply */ struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED) { fprintf(stderr, "new_onionreply called!\n"); abort(); } diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index 040e12f91..239cd6c9e 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -30,8 +30,6 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED, const struct half_chan *hc UNNEEDED, const u8 *cupdate UNNEEDED) { fprintf(stderr, "cupdate_different called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -61,22 +59,6 @@ const u8 *gossip_store_get_private_update(const tal_t *ctx UNNEEDED, void gossip_store_mark_channel_deleted(struct gossip_store *gs UNNEEDED, const struct short_channel_id *scid UNNEEDED) { fprintf(stderr, "gossip_store_mark_channel_deleted called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } /* Generated stub for memleak_add_helper_ */ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, const tal_t *)){ } diff --git a/lightningd/Makefile b/lightningd/Makefile index cf997370c..559387d2f 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -101,17 +101,16 @@ LIGHTNINGD_COMMON_OBJS := \ common/htlc_wire.o \ common/key_derive.o \ common/keyset.o \ - common/json.o \ - common/json_helpers.o \ + common/json_param.o \ + common/json_parse.o \ + common/json_parse_simple.o \ common/json_stream.o \ - common/json_tok.o \ common/lease_rates.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ common/onion.o \ common/onionreply.o \ - common/param.o \ common/penalty_base.o \ common/per_peer_state.o \ common/permute_tx.o \ diff --git a/lightningd/bitcoind.c b/lightningd/bitcoind.c index 711121a13..72472ccb0 100644 --- a/lightningd/bitcoind.c +++ b/lightningd/bitcoind.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 9b0d894d4..e85f3696f 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/lightningd/channel.c b/lightningd/channel.c index 06a7c6361..76b6a34ed 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 9c908b586..acf9fa13e 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -2,10 +2,9 @@ #include #include #include -#include -#include +#include +#include #include -#include #include #include #include diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 71f39bca8..fbbf8d426 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -12,9 +12,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index a6f3db94d..3ef116a76 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -4,10 +4,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include @@ -17,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/lightningd/datastore.c b/lightningd/datastore.c index 74b8a7cfc..828f22047 100644 --- a/lightningd/datastore.c +++ b/lightningd/datastore.c @@ -1,8 +1,8 @@ #include "config.h" #include #include -#include -#include +#include +#include #include #include diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index cac1152aa..9156f027c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -9,9 +9,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 0de65d194..0dfd9f32c 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -3,9 +3,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include #include diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index 5145f9095..d74eee2dd 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -5,9 +5,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include #include diff --git a/lightningd/invoice.c b/lightningd/invoice.c index affd55edf..a0097cb61 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -9,11 +9,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #include #include diff --git a/lightningd/json.c b/lightningd/json.c index 93e30f2b8..b420e47d4 100644 --- a/lightningd/json.c +++ b/lightningd/json.c @@ -1,8 +1,8 @@ #include "config.h" +#include #include #include -#include -#include +#include #include #include diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index 6cba43a34..f9ece1ce4 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -22,10 +22,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include diff --git a/lightningd/jsonrpc.h b/lightningd/jsonrpc.h index 1455891d4..8f090801e 100644 --- a/lightningd/jsonrpc.h +++ b/lightningd/jsonrpc.h @@ -3,7 +3,6 @@ #include "config.h" #include #include -#include #include #include diff --git a/lightningd/log.c b/lightningd/log.c index 362eedce3..11a66a092 100644 --- a/lightningd/log.c +++ b/lightningd/log.c @@ -7,9 +7,8 @@ #include #include #include -#include +#include #include -#include #include #include #include diff --git a/lightningd/memdump.c b/lightningd/memdump.c index 952355bf8..d0deabaa4 100644 --- a/lightningd/memdump.c +++ b/lightningd/memdump.c @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/lightningd/notification.c b/lightningd/notification.c index 79f41980c..8f1528a67 100644 --- a/lightningd/notification.c +++ b/lightningd/notification.c @@ -1,6 +1,5 @@ #include "config.h" #include -#include #include #include #include diff --git a/lightningd/offer.c b/lightningd/offer.c index c97ff9b4e..f80a7b39c 100644 --- a/lightningd/offer.c +++ b/lightningd/offer.c @@ -5,9 +5,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include #include diff --git a/lightningd/onion_message.c b/lightningd/onion_message.c index ae05c7c8f..42f61e2fc 100644 --- a/lightningd/onion_message.c +++ b/lightningd/onion_message.c @@ -2,9 +2,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index ab656fc82..e21f61bcf 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -9,10 +9,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include diff --git a/lightningd/options.c b/lightningd/options.c index b195acb6c..590f17e19 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -12,9 +12,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/lightningd/pay.c b/lightningd/pay.c index f13f3a16d..e6c3c9c1a 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -3,11 +3,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #include #include diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index bfd2e5af6..d265eb2aa 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -20,11 +20,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #include #include diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index be631a8ea..ae4dd2ecd 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index be84af86d..db062591a 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -6,11 +6,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #include #include diff --git a/lightningd/ping.c b/lightningd/ping.c index 144dbe8fa..b637f739b 100644 --- a/lightningd/ping.c +++ b/lightningd/ping.c @@ -1,7 +1,6 @@ #include "config.h" #include -#include -#include +#include #include #include #include diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 9dcbd3aac..f69258633 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/lightningd/plugin_control.c b/lightningd/plugin_control.c index d60b397c8..743584438 100644 --- a/lightningd/plugin_control.c +++ b/lightningd/plugin_control.c @@ -2,9 +2,8 @@ #include #include #include -#include +#include #include -#include #include #include #include diff --git a/lightningd/plugin_hook.c b/lightningd/plugin_hook.c index 9b3e83cd1..afdffca88 100644 --- a/lightningd/plugin_hook.c +++ b/lightningd/plugin_hook.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include diff --git a/lightningd/routehint.c b/lightningd/routehint.c index 86193904b..ce15ee27c 100644 --- a/lightningd/routehint.c +++ b/lightningd/routehint.c @@ -1,6 +1,6 @@ #include "config.h" #include -#include +#include #include #include #include diff --git a/lightningd/signmessage.c b/lightningd/signmessage.c index c2236d5cc..2624c582c 100644 --- a/lightningd/signmessage.c +++ b/lightningd/signmessage.c @@ -1,9 +1,7 @@ #include "config.h" #include #include -#include -#include -#include +#include #include #include #include diff --git a/lightningd/test/Makefile b/lightningd/test/Makefile index 660a7aeee..f9b10b466 100644 --- a/lightningd/test/Makefile +++ b/lightningd/test/Makefile @@ -15,7 +15,7 @@ LIGHTNINGD_TEST_COMMON_OBJS := \ common/daemon_conn.o \ common/htlc_state.o \ common/htlc_wire.o \ - common/json.o \ + common/json_parse_simple.o \ common/key_derive.o \ common/pseudorand.o \ common/random_select.o \ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index b8d9fed13..278c6d0c7 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -111,16 +111,6 @@ void htlcs_notify_new_block(struct lightningd *ld UNNEEDED, u32 height UNNEEDED) void htlcs_resubmit(struct lightningd *ld UNNEEDED, struct htlc_in_map *unconnected_htlcs_in UNNEEDED) { fprintf(stderr, "htlcs_resubmit called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index fab4c8a48..b6c34c78f 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -331,23 +331,38 @@ void json_add_amount_sat_msat(struct json_stream *result UNNEEDED, void json_add_bolt11(struct json_stream *response UNNEEDED, const struct bolt11 *b11 UNNEEDED) { fprintf(stderr, "json_add_bolt11 called!\n"); abort(); } +/* Generated stub for json_add_bool */ +void json_add_bool(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + bool value UNNEEDED) +{ fprintf(stderr, "json_add_bool called!\n"); abort(); } +/* Generated stub for json_add_escaped_string */ +void json_add_escaped_string(struct json_stream *result UNNEEDED, + const char *fieldname UNNEEDED, + const struct json_escape *esc TAKES UNNEEDED) +{ fprintf(stderr, "json_add_escaped_string called!\n"); abort(); } +/* Generated stub for json_add_hex_talarr */ +void json_add_hex_talarr(struct json_stream *result UNNEEDED, + const char *fieldname UNNEEDED, + const tal_t *data UNNEEDED) +{ fprintf(stderr, "json_add_hex_talarr called!\n"); abort(); } +/* Generated stub for json_add_invstring */ +void json_add_invstring(struct json_stream *result UNNEEDED, const char *invstring UNNEEDED) +{ fprintf(stderr, "json_add_invstring called!\n"); abort(); } /* Generated stub for json_add_log */ void json_add_log(struct json_stream *result UNNEEDED, const struct log_book *lr UNNEEDED, const struct node_id *node_id UNNEEDED, enum log_level minlevel UNNEEDED) { fprintf(stderr, "json_add_log called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } /* Generated stub for json_add_node_id */ void json_add_node_id(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "json_add_node_id called!\n"); abort(); } +/* Generated stub for json_add_num */ +void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + unsigned int value UNNEEDED) +{ fprintf(stderr, "json_add_num called!\n"); abort(); } /* Generated stub for json_add_preimage */ void json_add_preimage(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const struct preimage *preimage UNNEEDED) @@ -366,6 +381,18 @@ void json_add_short_channel_id(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED, const struct short_channel_id *id UNNEEDED) { fprintf(stderr, "json_add_short_channel_id called!\n"); abort(); } +/* Generated stub for json_add_string */ +void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value TAKES UNNEEDED) +{ fprintf(stderr, "json_add_string called!\n"); abort(); } +/* Generated stub for json_add_stringn */ +void json_add_stringn(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + const char *value TAKES UNNEEDED, size_t value_len UNNEEDED) +{ fprintf(stderr, "json_add_stringn called!\n"); abort(); } +/* Generated stub for json_add_timeiso */ +void json_add_timeiso(struct json_stream *result UNNEEDED, + const char *fieldname UNNEEDED, + struct timeabs *time UNNEEDED) +{ fprintf(stderr, "json_add_timeiso called!\n"); abort(); } /* Generated stub for json_add_tx */ void json_add_tx(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, @@ -375,6 +402,14 @@ void json_add_tx(struct json_stream *result UNNEEDED, void json_add_txid(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const struct bitcoin_txid *txid UNNEEDED) { fprintf(stderr, "json_add_txid called!\n"); abort(); } +/* Generated stub for json_add_u32 */ +void json_add_u32(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + uint32_t value UNNEEDED) +{ fprintf(stderr, "json_add_u32 called!\n"); abort(); } +/* Generated stub for json_add_u64 */ +void json_add_u64(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + uint64_t value UNNEEDED) +{ fprintf(stderr, "json_add_u64 called!\n"); abort(); } /* Generated stub for json_add_uncommitted_channel */ void json_add_uncommitted_channel(struct json_stream *response UNNEEDED, const struct uncommitted_channel *uc UNNEEDED) @@ -389,16 +424,19 @@ 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_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } /* Generated stub for json_object_start */ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) { fprintf(stderr, "json_object_start called!\n"); abort(); } +/* Generated stub for json_scan */ +const char *json_scan(const tal_t *ctx UNNEEDED, + const char *buffer UNNEEDED, + const jsmntok_t *tok UNNEEDED, + const char *guide UNNEEDED, + ...) +{ fprintf(stderr, "json_scan called!\n"); abort(); } /* Generated stub for json_stream_fail */ struct json_stream *json_stream_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED, @@ -421,10 +459,21 @@ bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "json_to_node_id called!\n"); abort(); } +/* Generated stub for json_to_number */ +bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + unsigned int *num UNNEEDED) +{ fprintf(stderr, "json_to_number called!\n"); abort(); } /* Generated stub for json_to_short_channel_id */ bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct short_channel_id *scid UNNEEDED) { fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } +/* Generated stub for json_to_u16 */ +bool json_to_u16(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint16_t *num UNNEEDED) +{ fprintf(stderr, "json_to_u16 called!\n"); abort(); } +/* Generated stub for json_tok_bin_from_hex */ +u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); } /* Generated stub for json_tok_channel_id */ bool json_tok_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct channel_id *cid UNNEEDED) diff --git a/lightningd/test/run-jsonrpc.c b/lightningd/test/run-jsonrpc.c index 87090fb7c..a3d15eaa7 100644 --- a/lightningd/test/run-jsonrpc.c +++ b/lightningd/test/run-jsonrpc.c @@ -30,10 +30,9 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for json_add_sha256 */ -void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, - const struct sha256 *hash UNNEEDED) -{ fprintf(stderr, "json_add_sha256 called!\n"); abort(); } +/* Generated stub for json_to_errcode */ +bool json_to_errcode(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, errcode_t *errcode UNNEEDED) +{ fprintf(stderr, "json_to_errcode called!\n"); abort(); } /* Generated stub for json_to_pubkey */ bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct pubkey *pubkey UNNEEDED) diff --git a/lightningd/test/run-log-pruning.c b/lightningd/test/run-log-pruning.c index 3db0a81dc..9449cbc82 100644 --- a/lightningd/test/run-log-pruning.c +++ b/lightningd/test/run-log-pruning.c @@ -27,6 +27,11 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for json_add_hex_talarr */ +void json_add_hex_talarr(struct json_stream *result UNNEEDED, + const char *fieldname UNNEEDED, + const tal_t *data UNNEEDED) +{ fprintf(stderr, "json_add_hex_talarr called!\n"); abort(); } /* Generated stub for json_add_member */ void json_add_member(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED, @@ -38,16 +43,23 @@ void json_add_node_id(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "json_add_node_id called!\n"); abort(); } +/* Generated stub for json_add_num */ +void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + unsigned int value UNNEEDED) +{ fprintf(stderr, "json_add_num called!\n"); abort(); } +/* Generated stub for json_add_string */ +void json_add_string(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const char *value TAKES UNNEEDED) +{ fprintf(stderr, "json_add_string called!\n"); abort(); } +/* Generated stub for json_add_time */ +void json_add_time(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, + struct timespec ts UNNEEDED) +{ fprintf(stderr, "json_add_time called!\n"); abort(); } /* Generated stub for json_array_end */ void json_array_end(struct json_stream *js UNNEEDED) { fprintf(stderr, "json_array_end called!\n"); abort(); } /* 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_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct 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(); } diff --git a/lightningd/test/run-shuffle_fds.c b/lightningd/test/run-shuffle_fds.c index 0981f69a3..83b0e3a52 100644 --- a/lightningd/test/run-shuffle_fds.c +++ b/lightningd/test/run-shuffle_fds.c @@ -75,16 +75,6 @@ bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDE /* Generated stub for fromwire_status_version */ bool fromwire_status_version(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **version UNNEEDED) { fprintf(stderr, "fromwire_status_version called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } /* Generated stub for log_ */ void log_(struct log *log UNNEEDED, enum log_level level UNNEEDED, const struct node_id *node_id UNNEEDED, diff --git a/plugins/Makefile b/plugins/Makefile index c69297569..7b32bb82a 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -134,14 +134,13 @@ PLUGIN_COMMON_OBJS := \ common/daemon.o \ common/features.o \ common/hash_u5.o \ - common/json.o \ - common/json_helpers.o \ + common/json_param.o \ + common/json_parse.o \ + common/json_parse_simple.o \ common/json_stream.o \ - common/json_tok.o \ common/lease_rates.o \ common/memleak.o \ common/node_id.o \ - common/param.o \ common/psbt_open.o \ common/pseudorand.o \ common/random_select.o \ diff --git a/plugins/autoclean.c b/plugins/autoclean.c index 360848c15..c4d29fc02 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -1,6 +1,7 @@ #include "config.h" #include -#include +#include +#include #include static u64 cycle_seconds = 0, expired_by = 86400; diff --git a/plugins/bcli.c b/plugins/bcli.c index 514aa0f62..ea98050ff 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -6,7 +6,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/plugins/chanbackup.c b/plugins/chanbackup.c index 85637ba2f..606a96ab7 100644 --- a/plugins/chanbackup.c +++ b/plugins/chanbackup.c @@ -8,9 +8,8 @@ #include #include #include -#include +#include #include -#include #include #include #include diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 088affb61..b7f3abe70 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/plugins/funder.c b/plugins/funder.c index 7f532fcd8..e4c1e0a1e 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -13,8 +13,9 @@ #include #include #include +#include #include -#include +#include #include #include #include diff --git a/plugins/keysend.c b/plugins/keysend.c index 17d8ccede..47fdc8fd5 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -1,9 +1,11 @@ #include "config.h" +#include #include #include #include #include -#include +#include +#include #include #include #include diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 553ce8448..feb6b4d81 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -3,6 +3,7 @@ #define LIGHTNING_PLUGINS_LIBPLUGIN_H #include "config.h" +#include #include #include #include @@ -11,12 +12,9 @@ #include #include #include -#include #include -#include #include #include -#include #include #include diff --git a/plugins/offers.c b/plugins/offers.c index bf37740a9..5ca4ea4d7 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/offers.h b/plugins/offers.h index 68feefa12..fd264d3c2 100644 --- a/plugins/offers.h +++ b/plugins/offers.h @@ -1,7 +1,6 @@ #ifndef LIGHTNING_PLUGINS_OFFERS_H #define LIGHTNING_PLUGINS_OFFERS_H #include "config.h" -#include struct command_result; struct command; diff --git a/plugins/offers_inv_hook.c b/plugins/offers_inv_hook.c index 3e2433362..146750e94 100644 --- a/plugins/offers_inv_hook.c +++ b/plugins/offers_inv_hook.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/offers_offer.c b/plugins/offers_offer.c index a7bebf17d..ee0968830 100644 --- a/plugins/offers_offer.c +++ b/plugins/offers_offer.c @@ -4,7 +4,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/plugins/pay.c b/plugins/pay.c index 0ccde645b..0e309b33b 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/plugins/spender/fundchannel.c b/plugins/spender/fundchannel.c index 5b235f911..51332c6c1 100644 --- a/plugins/spender/fundchannel.c +++ b/plugins/spender/fundchannel.c @@ -1,7 +1,7 @@ #include "config.h" #include +#include #include -#include #include static struct command_result * diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 4d0c2c75b..b721d73c4 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/plugins/spender/multiwithdraw.c b/plugins/spender/multiwithdraw.c index b06d09756..4bd7605f0 100644 --- a/plugins/spender/multiwithdraw.c +++ b/plugins/spender/multiwithdraw.c @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/plugins/topology.c b/plugins/topology.c index c2ce34ce0..dc4f2fc55 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -6,8 +6,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/plugins/txprepare.c b/plugins/txprepare.c index 85ff84b1a..2a767d95a 100644 --- a/plugins/txprepare.c +++ b/plugins/txprepare.c @@ -2,8 +2,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/tests/plugins/Makefile b/tests/plugins/Makefile index 3f2e6e3aa..3b2548221 100644 --- a/tests/plugins/Makefile +++ b/tests/plugins/Makefile @@ -8,7 +8,7 @@ $(PLUGIN_TESTLIBPLUGIN_OBJS): $(PLUGIN_LIB_HEADER) PLUGIN_TESTSELFDISABLE_AFTER_GETMANIFEST_SRC := tests/plugins/test_selfdisable_after_getmanifest.c PLUGIN_TESTSELFDISABLE_AFTER_GETMANIFEST_OBJS := $(PLUGIN_TESTSELFDISABLE_AFTER_GETMANIFEST_SRC:.c=.o) -tests/plugins/test_selfdisable_after_getmanifest: bitcoin/chainparams.o $(PLUGIN_TESTSELFDISABLE_AFTER_GETMANIFEST_OBJS) common/autodata.o common/json.o common/json_stream.o common/setup.o common/utils.o $(JSMN_OBJS) $(CCAN_OBJS) +tests/plugins/test_selfdisable_after_getmanifest: bitcoin/chainparams.o $(PLUGIN_TESTSELFDISABLE_AFTER_GETMANIFEST_OBJS) common/autodata.o common/json_parse_simple.o common/setup.o common/utils.o $(JSMN_OBJS) $(CCAN_OBJS) # Make sure these depend on everything. ALL_TEST_PROGRAMS += tests/plugins/test_libplugin tests/plugins/test_selfdisable_after_getmanifest diff --git a/tests/plugins/test_libplugin.c b/tests/plugins/test_libplugin.c index bb786a1b8..a93f975ad 100644 --- a/tests/plugins/test_libplugin.c +++ b/tests/plugins/test_libplugin.c @@ -1,7 +1,8 @@ #include "config.h" #include #include -#include +#include +#include #include #include diff --git a/tests/plugins/test_selfdisable_after_getmanifest.c b/tests/plugins/test_selfdisable_after_getmanifest.c index 443aae09b..228b4b241 100644 --- a/tests/plugins/test_selfdisable_after_getmanifest.c +++ b/tests/plugins/test_selfdisable_after_getmanifest.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/wallet/reservation.c b/wallet/reservation.c index f36622536..4f40e4b30 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -6,10 +6,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 88df58ab3..e7be2d410 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -6,10 +6,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include