diff --git a/doc/lightning-waitanyinvoice.7 b/doc/lightning-waitanyinvoice.7
index 411a7c9db..bd0c59d36 100644
--- a/doc/lightning-waitanyinvoice.7
+++ b/doc/lightning-waitanyinvoice.7
@@ -2,12 +2,12 @@
.\" Title: lightning-waitanyinvoice
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 01/23/2017
+.\" Date: 12/26/2017
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
-.TH "LIGHTNING\-WAITANYIN" "7" "01/23/2017" "\ \&" "\ \&"
+.TH "LIGHTNING\-WAITANYIN" "7" "12/26/2017" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -31,15 +31,17 @@
lightning-waitanyinvoice \- Protocol for waiting for payments\&.
.SH "SYNOPSIS"
.sp
-\fBwaitanyinvoice\fR [\fIlastlabel\fR]
+\fBwaitanyinvoice\fR [\fIlastpay_index\fR]
.SH "DESCRIPTION"
.sp
-The \fBwaitanyinvoice\fR RPC command waits until an invoice is paid, then returns a single entry as per \fBlistinvoice\fR\&. It will not return for any invoices paid prior to or including \fIlastlabel\fR\&.
+The \fBwaitanyinvoice\fR RPC command waits until an invoice is paid, then returns a single entry as per \fBlistinvoice\fR\&. It will not return for any invoices paid prior to or including the \fIlastpay_index\fR\&.
.sp
-This is usually called iteratively: once with no arguments, then repeatedly with the returned \fIlabel\fR entry\&. This ensures that no paid invoice is missed\&.
+This is usually called iteratively: once with no arguments, then repeatedly with the returned \fIpay_index\fR entry\&. This ensures that no paid invoice is missed\&.
+.sp
+The \fIpay_index\fR is a monotonically\-increasing number assigned to an invoice when it gets paid\&. The first valid \fIpay_index\fR is 1; specifying \fIlastpay_index\fR of 0 equivalent to not specifying a \fIlastpay_index\fR\&. Negative \fIlastpay_index\fR is invalid\&.
.SH "RETURN VALUE"
.sp
-On success, the \fIrhash\fR, \fIlabel\fR, and \fImsatoshi\fR will be returned\&.
+On success, the \fIrhash\fR, \fIlabel\fR, \fIpay_index\fR, and \fImsatoshi\fR will be returned\&.
.SH "AUTHOR"
.sp
Rusty Russell is mainly responsible\&.
diff --git a/doc/lightning-waitanyinvoice.7.txt b/doc/lightning-waitanyinvoice.7.txt
index cb33443a0..df80792cf 100644
--- a/doc/lightning-waitanyinvoice.7.txt
+++ b/doc/lightning-waitanyinvoice.7.txt
@@ -8,21 +8,27 @@ lightning-waitanyinvoice - Protocol for waiting for payments.
SYNOPSIS
--------
-*waitanyinvoice* ['lastlabel']
+*waitanyinvoice* ['lastpay_index']
DESCRIPTION
-----------
The *waitanyinvoice* RPC command waits until an invoice is paid, then
returns a single entry as per *listinvoice*. It will not return for
-any invoices paid prior to or including 'lastlabel'.
+any invoices paid prior to or including the 'lastpay_index'.
This is usually called iteratively: once with no arguments, then
-repeatedly with the returned 'label' entry. This ensures that no paid
+repeatedly with the returned 'pay_index' entry. This ensures that no paid
invoice is missed.
+The 'pay_index' is a monotonically-increasing number assigned to an
+invoice when it gets paid. The first valid 'pay_index' is 1; specifying
+'lastpay_index' of 0 equivalent to not specifying a 'lastpay_index'.
+Negative 'lastpay_index' is invalid.
+
+
RETURN VALUE
------------
-On success, the 'rhash', 'label', and 'msatoshi' will be returned.
+On success, the 'rhash', 'label', 'pay_index', and 'msatoshi' will be returned.
//FIXME:Enumerate errors
diff --git a/lightningd/invoice.c b/lightningd/invoice.c
index 1a8991fc9..ba42ae145 100644
--- a/lightningd/invoice.c
+++ b/lightningd/invoice.c
@@ -83,6 +83,8 @@ static void tell_waiter(struct command *cmd, const struct invoice *paid)
json_add_hex(response, "rhash", &paid->rhash, sizeof(paid->rhash));
json_add_u64(response, "msatoshi", paid->msatoshi);
json_add_bool(response, "complete", paid->state == PAID);
+ if (paid->state == PAID)
+ json_add_u64(response, "pay_index", paid->pay_index);
json_object_end(response);
command_success(cmd, response);
}
@@ -98,7 +100,11 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice)
invoice->state = PAID;
- /* Tell all the waitanyinvoice waiters about the new paid invoice */
+ /* wallet_invoice_save updates pay_index member,
+ * which tell_waiter needs. */
+ wallet_invoice_save(ld->wallet, invoice);
+
+ /* Tell all the waiters about the new paid invoice */
while ((w = list_pop(&invs->invoice_waiters,
struct invoice_waiter,
list)) != NULL)
@@ -109,8 +115,6 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice)
list)) != NULL)
tell_waiter(w->cmd, invoice);
- wallet_invoice_save(ld->wallet, invoice);
-
/* Also mark the payment in the history table as complete */
wallet_payment_set_status(ld->wallet, &invoice->rhash, PAYMENT_COMPLETE);
}
@@ -389,44 +393,43 @@ AUTODATA(json_command, &delinvoice_command);
static void json_waitanyinvoice(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
- jsmntok_t *labeltok;
- const char *label = NULL;
+ jsmntok_t *pay_indextok;
+ u64 pay_index;
struct invoice_waiter *w;
struct invoices *invs = cmd->ld->invoices;
- int res;
+ bool res;
struct wallet *wallet = cmd->ld->wallet;
char* outlabel;
struct sha256 outrhash;
u64 outmsatoshi;
+ u64 outpay_index;
struct json_result *response;
if (!json_get_params(buffer, params,
- "?label", &labeltok,
+ "?lastpay_index", &pay_indextok,
NULL)) {
command_fail(cmd, "Invalid arguments");
return;
}
- if (!labeltok) {
- label = NULL;
+ if (!pay_indextok) {
+ pay_index = 0;
} else {
- label = tal_strndup(cmd, buffer + labeltok->start,
- labeltok->end - labeltok->start);
+ if (!json_tok_u64(buffer, pay_indextok, &pay_index)) {
+ command_fail(cmd, "'%.*s' is not a valid number",
+ pay_indextok->end - pay_indextok->start,
+ buffer + pay_indextok->start);
+ return;
+ }
}
/* Find next paid invoice. */
- res = wallet_invoice_nextpaid(cmd, wallet, label,
- &outlabel, &outrhash, &outmsatoshi);
- label = tal_free(label);
-
- /* If we failed to find label, error it. */
- if (res == -1) {
- command_fail(cmd, "Label not found");
- return;
- }
+ res = wallet_invoice_nextpaid(cmd, wallet, pay_index,
+ &outlabel, &outrhash,
+ &outmsatoshi, &outpay_index);
/* If we found one, return it. */
- if (res == 1) {
+ if (res) {
response = new_json_result(cmd);
json_object_start(response, NULL);
@@ -434,6 +437,7 @@ static void json_waitanyinvoice(struct command *cmd,
json_add_hex(response, "rhash", &outrhash, sizeof(outrhash));
json_add_u64(response, "msatoshi", outmsatoshi);
json_add_bool(response, "complete", true);
+ json_add_u64(response, "pay_index", outpay_index);
json_object_end(response);
command_success(cmd, response);
@@ -454,8 +458,8 @@ static void json_waitanyinvoice(struct command *cmd,
static const struct json_command waitanyinvoice_command = {
"waitanyinvoice",
json_waitanyinvoice,
- "Wait for the next invoice to be paid, after {label} (if supplied)))",
- "Returns {label}, {rhash} and {msatoshi} on success. "
+ "Wait for the next invoice to be paid, after {lastpay_index} (if supplied)))",
+ "Returns {label}, {rhash}, {msatoshi}, and {pay_index} on success. "
};
AUTODATA(json_command, &waitanyinvoice_command);
diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py
index 6b1c1c194..ffe08c694 100644
--- a/tests/test_lightningd.py
+++ b/tests/test_lightningd.py
@@ -2435,20 +2435,22 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.pay(inv2['bolt11'])
r = f.result(timeout=5)
assert r['label'] == 'inv1'
+ pay_index = r['pay_index']
# This one should return immediately with inv2
- r = self.executor.submit(l2.rpc.waitanyinvoice, 'inv1').result(timeout=5)
+ r = self.executor.submit(l2.rpc.waitanyinvoice, pay_index).result(timeout=5)
assert r['label'] == 'inv2'
+ pay_index = r['pay_index']
# Now spawn the next waiter
- f = self.executor.submit(l2.rpc.waitanyinvoice, 'inv2')
+ f = self.executor.submit(l2.rpc.waitanyinvoice, pay_index)
time.sleep(1)
assert not f.done()
l1.rpc.pay(inv3['bolt11'])
r = f.result(timeout=5)
assert r['label'] == 'inv3'
- self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'doesntexist')
+ self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'non-number')
def test_waitanyinvoice_reversed(self):
@@ -2471,10 +2473,11 @@ class LightningDTests(BaseLightningDTests):
# Wait - should not block, should return inv2
r = self.executor.submit(l2.rpc.waitanyinvoice).result(timeout=5)
assert r['label'] == 'inv2'
+ pay_index = r['pay_index']
# Pay inv1
l1.rpc.pay(inv1['bolt11'])
# Wait inv2 - should not block, should return inv1
- r = self.executor.submit(l2.rpc.waitanyinvoice, 'inv2').result(timeout=5)
+ r = self.executor.submit(l2.rpc.waitanyinvoice, pay_index).result(timeout=5)
assert r['label'] == 'inv1'
def test_channel_reenable(self):
diff --git a/wallet/wallet.c b/wallet/wallet.c
index 7060c95b4..ab8a44972 100644
--- a/wallet/wallet.c
+++ b/wallet/wallet.c
@@ -1125,49 +1125,31 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
return true;
}
-int wallet_invoice_nextpaid(const tal_t *cxt,
- const struct wallet *wallet,
- const char *labelz,
- char **outlabel,
- struct sha256 *outrhash,
- u64 *outmsatoshi)
+bool wallet_invoice_nextpaid(const tal_t *cxt,
+ const struct wallet *wallet,
+ u64 pay_index,
+ char **outlabel,
+ struct sha256 *outrhash,
+ u64 *outmsatoshi,
+ u64 *outpay_index)
{
sqlite3_stmt *stmt;
int res;
- u64 pay_index;
/* Generate query. */
- if (labelz) {
- /* Find label. */
- stmt = db_prepare(wallet->db,
- "SELECT pay_index FROM invoices WHERE label=?;");
- sqlite3_bind_text(stmt, 1, labelz, strlen(labelz), SQLITE_TRANSIENT);
- res = sqlite3_step(stmt);
- if (res != SQLITE_ROW) {
- sqlite3_finalize(stmt);
- return -1;
- }
- pay_index = sqlite3_column_int64(stmt, 0);
- sqlite3_finalize(stmt);
-
- stmt = db_prepare(wallet->db,
- "SELECT label, payment_hash, msatoshi FROM invoices"
- " WHERE pay_index NOT NULL"
- " AND pay_index > ?"
- " ORDER BY pay_index ASC LIMIT 1;");
- sqlite3_bind_int64(stmt, 1, pay_index);
- } else {
- stmt = db_prepare(wallet->db,
- "SELECT label, payment_hash, msatoshi FROM invoices"
- " WHERE pay_index NOT NULL"
- " ORDER BY pay_index ASC LIMIT 1;");
- }
+ stmt = db_prepare(wallet->db,
+ "SELECT label, payment_hash, msatoshi, pay_index"
+ " FROM invoices"
+ " WHERE pay_index NOT NULL"
+ " AND pay_index > ?"
+ " ORDER BY pay_index ASC LIMIT 1;");
+ sqlite3_bind_int64(stmt, 1, pay_index);
res = sqlite3_step(stmt);
if (res != SQLITE_ROW) {
/* No paid invoice found. */
sqlite3_finalize(stmt);
- return 0;
+ return false;
} else {
/* Paid invoice found, return data. */
*outlabel = tal_strndup(cxt, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
@@ -1177,11 +1159,11 @@ int wallet_invoice_nextpaid(const tal_t *cxt,
*outmsatoshi = sqlite3_column_int64(stmt, 2);
+ *outpay_index = sqlite3_column_int64(stmt, 3);
+
sqlite3_finalize(stmt);
- return 1;
+ return true;
}
-
- return -1;
}
/* Acquire the next pay_index. */
diff --git a/wallet/wallet.h b/wallet/wallet.h
index ad911c1fa..1fa121189 100644
--- a/wallet/wallet.h
+++ b/wallet/wallet.h
@@ -333,28 +333,29 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
/**
* wallet_invoice_nextpaid -- Find a paid invoice.
*
- * Get the details (label, rhash, msatoshi) of the next paid
- * invoice after the invoice with the given label. If label is
- * `NULL`, get the details of the first paid invoice. Return -1
- * if label is non-`NULL` and is not found, 0 if no more paid
- * invoices after specified invoice (or no paid invoices if label
- * is `NULL`), 1 if the next paid invoice was found.
+ * Get the details (label, rhash, msatoshi, pay_index) of the first paid
+ * invoice greater than the given pay_index. Return false if no paid
+ * invoice found, return true if found. The first ever paid invoice will
+ * have a pay_index of 1 or greater, so giving a pay_index of 0 will get
+ * the first ever paid invoice if there is one.
*
* @ctx: Context to create the returned label.
* @wallet: Wallet to query
- * @labelz: The label to be queried (zero-terminated), or
- * `NULL` if first invoice is to be queried.
+ * @pay_index: The paid invoice returned will have pay_index greater
+ * than this argument.
* @outlabel: Pointer to label of found paid invoice. Caller
- * must free if this function returns 1.
+ * must free if this function returns true.
* @outrhash: Pointer to struct rhash to be filled.
* @outmsatoshi: Pointer to number of millisatoshis value to pay.
+ * @outpay_index: Pointer to pay_index of found paid invoice.
*/
-int wallet_invoice_nextpaid(const tal_t *cxt,
- const struct wallet *wallet,
- const char *labelz,
- char **outlabel,
- struct sha256 *outrhash,
- u64 *outmsatoshi);
+bool wallet_invoice_nextpaid(const tal_t *cxt,
+ const struct wallet *wallet,
+ u64 pay_index,
+ char **outlabel,
+ struct sha256 *outrhash,
+ u64 *outmsatoshi,
+ u64 *outpay_index);
/**
* wallet_invoice_save -- Save/update an invoice to the wallet