diff --git a/common/json_tok.c b/common/json_tok.c index b0b0d1cc2..faff0abc3 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -116,26 +117,6 @@ struct command_result *param_sha256(struct command *cmd, const char *name, name, tok->end - tok->start, buffer + tok->start); } -struct command_result *param_msat(struct command *cmd, const char *name, - const char *buffer, const jsmntok_t * tok, - u64 **msatoshi_val) -{ - if (json_tok_streq(buffer, tok, "any")) { - *msatoshi_val = NULL; - return NULL; - } - *msatoshi_val = tal(cmd, u64); - - if (json_to_u64(buffer, tok, *msatoshi_val) && *msatoshi_val != 0) - return NULL; - - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "'%s' should be a positive number or 'any', not '%.*s'", - name, - tok->end - tok->start, - buffer + tok->start); -} - struct command_result *param_percent(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, double **num) @@ -169,3 +150,30 @@ struct command_result *param_tok(struct command *cmd, const char *name, *out = tok; return NULL; } + +struct command_result *param_msat(struct command *cmd, const char *name, + const char *buffer, const jsmntok_t *tok, + struct amount_msat **msat) +{ + *msat = tal(cmd, struct amount_msat); + if (parse_amount_msat(*msat, buffer + tok->start, tok->end - tok->start)) + return NULL; + + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "'%s' should be a millisatoshi amount, not '%.*s'", + name, tok->end - tok->start, buffer + tok->start); +} + +struct command_result *param_sat(struct command *cmd, const char *name, + const char *buffer, const jsmntok_t *tok, + struct amount_sat **sat) +{ + *sat = tal(cmd, struct amount_sat); + if (parse_amount_sat(*sat, buffer + tok->start, tok->end - tok->start)) + return NULL; + + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "'%s' should be a satoshi amount, not '%.*s'", + name, tok->end - tok->start, buffer + tok->start); +} + diff --git a/common/json_tok.h b/common/json_tok.h index 0a0e33d1c..8284c915f 100644 --- a/common/json_tok.h +++ b/common/json_tok.h @@ -5,6 +5,8 @@ #include #include +struct amount_msat; +struct amount_sat; struct command; struct command_result; struct json_escaped; @@ -52,11 +54,6 @@ struct command_result *param_sha256(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, struct sha256 **hash); -/* Extract positive integer, or NULL if tok is 'any'. */ -struct command_result *param_msat(struct command *cmd, const char *name, - const char *buffer, const jsmntok_t * tok, - u64 **msatoshi_val); - /* Extract double in range [0.0, 100.0] */ struct command_result *param_percent(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, @@ -67,6 +64,16 @@ struct command_result *param_u64(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, uint64_t **num); +/* Extra msatoshi amount from this string */ +struct command_result *param_msat(struct command *cmd, const char *name, + const char *buffer, const jsmntok_t *tok, + struct amount_msat **msat); + +/* Extra satoshi amount from this string */ +struct command_result *param_sat(struct command *cmd, const char *name, + const char *buffer, const jsmntok_t *tok, + struct amount_sat **sat); + /* * Set the address of @out to @tok. Used as a callback by handlers that * want to unmarshal @tok themselves. diff --git a/common/test/run-param.c b/common/test/run-param.c index 7e67100d4..57c44d265 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -1,4 +1,5 @@ #include "config.h" +#include "../amount.c" #include "../json.c" #include "../json_escaped.c" #include "../json_tok.c" @@ -444,10 +445,10 @@ static void advanced(void) assert(param(cmd, j->buffer, j->toks, p_req("description", param_label, &label), - p_req("msat", param_msat, &msat), + p_req("msat", param_u64, &msat), p_req("tok", param_tok, &tok), - p_opt("msat_opt1", param_msat, &msat_opt1), - p_opt("msat_opt2", param_msat, &msat_opt2), + p_opt("msat_opt1", param_u64, &msat_opt1), + p_opt("msat_opt2", param_u64, &msat_opt2), NULL)); assert(label != NULL); assert(streq(label->s, "lightning")); @@ -472,8 +473,8 @@ static void advanced(void) u64 *msat2; struct json *j = json_parse(cmd, "[ 3 ]"); assert(param(cmd, j->buffer, j->toks, - p_opt_def("msat", param_msat, &msat, 23), - p_opt_def("msat2", param_msat, &msat2, 53), + p_opt_def("msat", param_u64, &msat, 23), + p_opt_def("msat2", param_u64, &msat2, 53), NULL)); assert(*msat == 3); assert(msat2); @@ -487,11 +488,10 @@ static void advanced_fail(void) struct json *j = json_parse(cmd, "[ 'anyx' ]"); u64 *msat; assert(!param(cmd, j->buffer, j->toks, - p_req("msat", param_msat, &msat), + p_req("msat", param_u64, &msat), NULL)); assert(check_fail()); - assert(strstr(fail_msg, "'msat' should be a positive" - " number or 'any', not 'anyx'")); + assert(strstr(fail_msg, "'msat' should be an unsigned 64 bit integer, not 'anyx'")); } } @@ -540,7 +540,7 @@ static void test_invoice(struct command *cmd, assert(cmd->mode == CMD_USAGE); if(!param(cmd, buffer, params, - p_req("msatoshi", param_msat, &msatoshi_val), + p_req("msatoshi", param_u64, &msatoshi_val), p_req("label", param_label, &label_val), p_req("description", param_escaped_string, &desc_val), p_opt("expiry", param_u64, &expiry), diff --git a/lightningd/Makefile b/lightningd/Makefile index a02438f84..16b9bed6a 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -14,6 +14,7 @@ default: lightningd-all # Common source we use. LIGHTNINGD_COMMON_OBJS := \ + common/amount.o \ common/base32.o \ common/bech32.o \ common/bech32_util.o \ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 76c315d72..4dab665dd 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -357,6 +358,27 @@ static struct route_info **unpack_routes(const tal_t *ctx, } #endif /* DEVELOPER */ +static struct command_result *param_msat_or_any(struct command *cmd, + const char *name, + const char *buffer, + const jsmntok_t *tok, + struct amount_msat **msat) +{ + if (json_tok_streq(buffer, tok, "any")) { + *msat = NULL; + return NULL; + } + *msat = tal(cmd, struct amount_msat); + if (parse_amount_msat(*msat, buffer + tok->start, tok->end - tok->start)) + return NULL; + + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "'%s' should be millisatoshis or 'any', not '%.*s'", + name, + tok->end - tok->start, + buffer + tok->start); +} + static struct command_result *json_invoice(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -364,7 +386,7 @@ static struct command_result *json_invoice(struct command *cmd, { const jsmntok_t *fallbacks; const jsmntok_t *preimagetok; - u64 *msatoshi_val; + struct amount_msat *msatoshi_val; struct invoice_info *info; const char *desc_val; const u8 **fallback_scripts = NULL; @@ -380,7 +402,7 @@ static struct command_result *json_invoice(struct command *cmd, info->cmd = cmd; if (!param(cmd, buffer, params, - p_req("msatoshi", param_msat, &msatoshi_val), + p_req("msatoshi", param_msat_or_any, &msatoshi_val), p_req("label", param_label, &info->label), p_req("description", param_escaped_string, &desc_val), p_opt_def("expiry", param_u64, &expiry, 3600), @@ -409,7 +431,8 @@ static struct command_result *json_invoice(struct command *cmd, } chainparams = get_chainparams(cmd->ld); - if (msatoshi_val && *msatoshi_val > chainparams->max_payment_msat) { + if (msatoshi_val + && msatoshi_val->millisatoshis > chainparams->max_payment_msat) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "msatoshi cannot exceed %"PRIu64 " millisatoshis", @@ -446,8 +469,11 @@ static struct command_result *json_invoice(struct command *cmd, /* Generate preimage hash. */ sha256(&rhash, &info->payment_preimage, sizeof(info->payment_preimage)); - /* Construct bolt11 string. */ - info->b11 = new_bolt11(info, msatoshi_val); + /* FIXME: Make bolt11 take struct amount_msat */ + if (msatoshi_val) + info->b11 = new_bolt11(info, &msatoshi_val->millisatoshis); + else + info->b11 = new_bolt11(info, NULL); info->b11->chain = chainparams; info->b11->timestamp = time_now().ts.tv_sec; info->b11->payment_hash = rhash; diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index b40608e11..101e8de9e 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -295,11 +295,6 @@ struct command_result *param_loglevel(struct command *cmd UNNEEDED, const jsmntok_t *tok UNNEEDED, enum log_level **level UNNEEDED) { fprintf(stderr, "param_loglevel called!\n"); abort(); } -/* Generated stub for param_msat */ -struct command_result *param_msat(struct command *cmd UNNEEDED, const char *name UNNEEDED, - const char *buffer UNNEEDED, const jsmntok_t * tok UNNEEDED, - u64 **msatoshi_val UNNEEDED) -{ fprintf(stderr, "param_msat called!\n"); abort(); } /* Generated stub for param_number */ struct command_result *param_number(struct command *cmd UNNEEDED, const char *name UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, @@ -332,6 +327,9 @@ struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, uint64_t **num UNNEEDED) { fprintf(stderr, "param_u64 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 peer_memleak_done */ void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED) { fprintf(stderr, "peer_memleak_done called!\n"); abort(); } diff --git a/plugins/Makefile b/plugins/Makefile index 1a128bd24..f5a248d5a 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -15,6 +15,7 @@ PLUGIN_COMMON_OBJS := \ bitcoin/signature.o \ bitcoin/tx.o \ bitcoin/varint.o \ + common/amount.o \ common/bech32.o \ common/bech32_util.o \ common/bolt11.o \