waitinvoice: RPC call for processing incoming invoices.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-09-06 16:47:49 +09:30
parent 27715f7732
commit c83fb1a2dd
6 changed files with 82 additions and 2 deletions

View File

@ -7,6 +7,11 @@
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
struct invoice_waiter {
struct list_node list;
struct command *cmd;
};
static struct invoice *find_inv(const struct list_head *list, static struct invoice *find_inv(const struct list_head *list,
const struct sha256 *rhash) const struct sha256 *rhash)
{ {
@ -65,12 +70,33 @@ void invoice_add(struct lightningd_state *dstate,
list_add(&dstate->unpaid, &invoice->list); list_add(&dstate->unpaid, &invoice->list);
} }
static void tell_waiter(struct command *cmd, const struct invoice *paid)
{
struct json_result *response = new_json_result(cmd);
json_object_start(response, NULL);
json_add_string(response, "label", paid->label);
json_add_hex(response, "rhash", &paid->rhash, sizeof(paid->rhash));
json_add_u64(response, "msatoshi", paid->msatoshi);
json_object_end(response);
command_success(cmd, response);
}
bool resolve_invoice(struct lightningd_state *dstate, bool resolve_invoice(struct lightningd_state *dstate,
struct invoice *invoice) struct invoice *invoice)
{ {
struct invoice_waiter *w;
invoice->paid_num = ++dstate->invoices_completed; invoice->paid_num = ++dstate->invoices_completed;
list_del_from(&dstate->unpaid, &invoice->list); list_del_from(&dstate->unpaid, &invoice->list);
list_add_tail(&dstate->paid, &invoice->list); list_add_tail(&dstate->paid, &invoice->list);
/* Tell all the waiters about the new paid invoice */
while ((w = list_pop(&dstate->invoice_waiters,
struct invoice_waiter,
list)) != NULL)
tell_waiter(w->cmd, invoice);
return db_resolve_invoice(dstate, invoice->label, invoice->paid_num); return db_resolve_invoice(dstate, invoice->label, invoice->paid_num);
} }
@ -247,3 +273,50 @@ const struct json_command delinvoice_command = {
"Returns {label}, {rhash} and {msatoshi} on success. " "Returns {label}, {rhash} and {msatoshi} on success. "
}; };
static void json_waitinvoice(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct invoice *i;
jsmntok_t *labeltok;
const char *label = NULL;
struct invoice_waiter *w;
if (!json_get_params(buffer, params,
"?label", &labeltok,
NULL)) {
command_fail(cmd, "Invalid arguments");
return;
}
if (!labeltok)
i = list_top(&cmd->dstate->paid, struct invoice, list);
else {
label = tal_strndup(cmd, buffer + labeltok->start,
labeltok->end - labeltok->start);
i = find_invoice_by_label(&cmd->dstate->paid, label);
if (!i) {
command_fail(cmd, "Label not found");
return;
}
i = list_next(&cmd->dstate->paid, i, list);
}
/* If we found one, return it. */
if (i) {
tell_waiter(cmd, i);
return;
}
/* Otherwise, wait. */
/* FIXME: Better to use io_wait directly? */
w = tal(cmd, struct invoice_waiter);
w->cmd = cmd;
list_add_tail(&cmd->dstate->invoice_waiters, &w->list);
}
const struct json_command waitinvoice_command = {
"waitinvoice",
json_waitinvoice,
"Wait for the next invoice to be paid, after {label} (if supplied)))",
"Returns {label}, {rhash} and {msatoshi} on success. "
};

View File

@ -292,6 +292,7 @@ static const struct json_command *cmdlist[] = {
&invoice_command, &invoice_command,
&listinvoice_command, &listinvoice_command,
&delinvoice_command, &delinvoice_command,
&waitinvoice_command,
&getroute_command, &getroute_command,
&sendpay_command, &sendpay_command,
&feerate_command, &feerate_command,

View File

@ -74,6 +74,7 @@ extern const struct json_command output_command;
extern const struct json_command invoice_command; extern const struct json_command invoice_command;
extern const struct json_command listinvoice_command; extern const struct json_command listinvoice_command;
extern const struct json_command delinvoice_command; extern const struct json_command delinvoice_command;
extern const struct json_command waitinvoice_command;
extern const struct json_command add_route_command; extern const struct json_command add_route_command;
extern const struct json_command routefail_command; extern const struct json_command routefail_command;
extern const struct json_command getroute_command; extern const struct json_command getroute_command;

View File

@ -258,6 +258,7 @@ static struct lightningd_state *lightningd_state(void)
list_head_init(&dstate->unpaid); list_head_init(&dstate->unpaid);
list_head_init(&dstate->paid); list_head_init(&dstate->paid);
dstate->invoices_completed = 0; dstate->invoices_completed = 0;
list_head_init(&dstate->invoice_waiters);
list_head_init(&dstate->addresses); list_head_init(&dstate->addresses);
dstate->dev_never_routefail = false; dstate->dev_never_routefail = false;
dstate->bitcoin_req_running = false; dstate->bitcoin_req_running = false;

View File

@ -113,6 +113,8 @@ struct lightningd_state {
/* Payments for r values we know about. */ /* Payments for r values we know about. */
struct list_head paid, unpaid; struct list_head paid, unpaid;
u64 invoices_completed; u64 invoices_completed;
/* Waiting for new invoices to be paid. */
struct list_head invoice_waiters;
/* All known nodes. */ /* All known nodes. */
struct node_map *nodes; struct node_map *nodes;

View File

@ -1077,6 +1077,8 @@ if [ ! -n "$MANUALCOMMIT" ]; then
[ "`lcli3 listinvoice RHASH5 | tr -s '\012\011\" ' ' '`" = "{ [ { label : RHASH5 , rhash : $RHASH5 , msatoshi : $HTLC_AMOUNT, complete : true } ] } " ] [ "`lcli3 listinvoice RHASH5 | tr -s '\012\011\" ' ' '`" = "{ [ { label : RHASH5 , rhash : $RHASH5 , msatoshi : $HTLC_AMOUNT, complete : true } ] } " ]
[ "`lcli3 waitinvoice | tr -s '\012\011\" ' ' '`" = "{ label : RHASH5 , rhash : $RHASH5 , msatoshi : $HTLC_AMOUNT } " ]
# Can't pay twice (try from node2) # Can't pay twice (try from node2)
ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT 1` ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT 1`
ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'` ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'`