diff --git a/daemon/invoice.c b/daemon/invoice.c index 38650a3c7..e4a59e7d6 100644 --- a/daemon/invoice.c +++ b/daemon/invoice.c @@ -7,6 +7,11 @@ #include #include +struct invoice_waiter { + struct list_node list; + struct command *cmd; +}; + static struct invoice *find_inv(const struct list_head *list, const struct sha256 *rhash) { @@ -65,12 +70,33 @@ void invoice_add(struct lightningd_state *dstate, 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, struct invoice *invoice) { + struct invoice_waiter *w; + invoice->paid_num = ++dstate->invoices_completed; list_del_from(&dstate->unpaid, &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); } @@ -247,3 +273,50 @@ const struct json_command delinvoice_command = { "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. " +}; diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index 51e6a8dc1..52220b348 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -292,6 +292,7 @@ static const struct json_command *cmdlist[] = { &invoice_command, &listinvoice_command, &delinvoice_command, + &waitinvoice_command, &getroute_command, &sendpay_command, &feerate_command, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index 4f97d7766..bf108cc81 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -74,6 +74,7 @@ extern const struct json_command output_command; extern const struct json_command invoice_command; extern const struct json_command listinvoice_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 routefail_command; extern const struct json_command getroute_command; diff --git a/daemon/lightningd.c b/daemon/lightningd.c index f9d03c43d..8df13b2dd 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -258,6 +258,7 @@ static struct lightningd_state *lightningd_state(void) list_head_init(&dstate->unpaid); list_head_init(&dstate->paid); dstate->invoices_completed = 0; + list_head_init(&dstate->invoice_waiters); list_head_init(&dstate->addresses); dstate->dev_never_routefail = false; dstate->bitcoin_req_running = false; diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 5d24c5bc2..88ccd4536 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -113,7 +113,9 @@ struct lightningd_state { /* Payments for r values we know about. */ struct list_head paid, unpaid; u64 invoices_completed; - + /* Waiting for new invoices to be paid. */ + struct list_head invoice_waiters; + /* All known nodes. */ struct node_map *nodes; diff --git a/daemon/test/test.sh b/daemon/test/test.sh index 8356b02bd..fe7fb773d 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -1076,7 +1076,9 @@ if [ ! -n "$MANUALCOMMIT" ]; then fi [ "`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) ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT 1` ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'`