mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
invoice: Modify waitanyinvoice interface to use pay_index.
This commit is contained in:
@@ -2,12 +2,12 @@
|
|||||||
.\" Title: lightning-waitanyinvoice
|
.\" Title: lightning-waitanyinvoice
|
||||||
.\" Author: [see the "AUTHOR" section]
|
.\" Author: [see the "AUTHOR" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 01/23/2017
|
.\" Date: 12/26/2017
|
||||||
.\" Manual: \ \&
|
.\" Manual: \ \&
|
||||||
.\" Source: \ \&
|
.\" Source: \ \&
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "LIGHTNING\-WAITANYIN" "7" "01/23/2017" "\ \&" "\ \&"
|
.TH "LIGHTNING\-WAITANYIN" "7" "12/26/2017" "\ \&" "\ \&"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@@ -31,15 +31,17 @@
|
|||||||
lightning-waitanyinvoice \- Protocol for waiting for payments\&.
|
lightning-waitanyinvoice \- Protocol for waiting for payments\&.
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
.sp
|
.sp
|
||||||
\fBwaitanyinvoice\fR [\fIlastlabel\fR]
|
\fBwaitanyinvoice\fR [\fIlastpay_index\fR]
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.sp
|
.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
|
.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"
|
.SH "RETURN VALUE"
|
||||||
.sp
|
.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"
|
.SH "AUTHOR"
|
||||||
.sp
|
.sp
|
||||||
Rusty Russell <rusty@rustcorp\&.com\&.au> is mainly responsible\&.
|
Rusty Russell <rusty@rustcorp\&.com\&.au> is mainly responsible\&.
|
||||||
|
|||||||
@@ -8,21 +8,27 @@ lightning-waitanyinvoice - Protocol for waiting for payments.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
*waitanyinvoice* ['lastlabel']
|
*waitanyinvoice* ['lastpay_index']
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
The *waitanyinvoice* RPC command waits until an invoice is paid, then
|
The *waitanyinvoice* RPC command waits until an invoice is paid, then
|
||||||
returns a single entry as per *listinvoice*. It will not return for
|
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
|
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.
|
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
|
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
|
//FIXME:Enumerate errors
|
||||||
|
|
||||||
|
|||||||
@@ -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_hex(response, "rhash", &paid->rhash, sizeof(paid->rhash));
|
||||||
json_add_u64(response, "msatoshi", paid->msatoshi);
|
json_add_u64(response, "msatoshi", paid->msatoshi);
|
||||||
json_add_bool(response, "complete", paid->state == PAID);
|
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);
|
json_object_end(response);
|
||||||
command_success(cmd, response);
|
command_success(cmd, response);
|
||||||
}
|
}
|
||||||
@@ -98,7 +100,11 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice)
|
|||||||
|
|
||||||
invoice->state = PAID;
|
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,
|
while ((w = list_pop(&invs->invoice_waiters,
|
||||||
struct invoice_waiter,
|
struct invoice_waiter,
|
||||||
list)) != NULL)
|
list)) != NULL)
|
||||||
@@ -109,8 +115,6 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice)
|
|||||||
list)) != NULL)
|
list)) != NULL)
|
||||||
tell_waiter(w->cmd, invoice);
|
tell_waiter(w->cmd, invoice);
|
||||||
|
|
||||||
wallet_invoice_save(ld->wallet, invoice);
|
|
||||||
|
|
||||||
/* Also mark the payment in the history table as complete */
|
/* Also mark the payment in the history table as complete */
|
||||||
wallet_payment_set_status(ld->wallet, &invoice->rhash, PAYMENT_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,
|
static void json_waitanyinvoice(struct command *cmd,
|
||||||
const char *buffer, const jsmntok_t *params)
|
const char *buffer, const jsmntok_t *params)
|
||||||
{
|
{
|
||||||
jsmntok_t *labeltok;
|
jsmntok_t *pay_indextok;
|
||||||
const char *label = NULL;
|
u64 pay_index;
|
||||||
struct invoice_waiter *w;
|
struct invoice_waiter *w;
|
||||||
struct invoices *invs = cmd->ld->invoices;
|
struct invoices *invs = cmd->ld->invoices;
|
||||||
int res;
|
bool res;
|
||||||
struct wallet *wallet = cmd->ld->wallet;
|
struct wallet *wallet = cmd->ld->wallet;
|
||||||
char* outlabel;
|
char* outlabel;
|
||||||
struct sha256 outrhash;
|
struct sha256 outrhash;
|
||||||
u64 outmsatoshi;
|
u64 outmsatoshi;
|
||||||
|
u64 outpay_index;
|
||||||
struct json_result *response;
|
struct json_result *response;
|
||||||
|
|
||||||
if (!json_get_params(buffer, params,
|
if (!json_get_params(buffer, params,
|
||||||
"?label", &labeltok,
|
"?lastpay_index", &pay_indextok,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
command_fail(cmd, "Invalid arguments");
|
command_fail(cmd, "Invalid arguments");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!labeltok) {
|
if (!pay_indextok) {
|
||||||
label = NULL;
|
pay_index = 0;
|
||||||
} else {
|
} else {
|
||||||
label = tal_strndup(cmd, buffer + labeltok->start,
|
if (!json_tok_u64(buffer, pay_indextok, &pay_index)) {
|
||||||
labeltok->end - labeltok->start);
|
command_fail(cmd, "'%.*s' is not a valid number",
|
||||||
|
pay_indextok->end - pay_indextok->start,
|
||||||
|
buffer + pay_indextok->start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find next paid invoice. */
|
/* Find next paid invoice. */
|
||||||
res = wallet_invoice_nextpaid(cmd, wallet, label,
|
res = wallet_invoice_nextpaid(cmd, wallet, pay_index,
|
||||||
&outlabel, &outrhash, &outmsatoshi);
|
&outlabel, &outrhash,
|
||||||
label = tal_free(label);
|
&outmsatoshi, &outpay_index);
|
||||||
|
|
||||||
/* If we failed to find label, error it. */
|
|
||||||
if (res == -1) {
|
|
||||||
command_fail(cmd, "Label not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found one, return it. */
|
/* If we found one, return it. */
|
||||||
if (res == 1) {
|
if (res) {
|
||||||
response = new_json_result(cmd);
|
response = new_json_result(cmd);
|
||||||
|
|
||||||
json_object_start(response, NULL);
|
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_hex(response, "rhash", &outrhash, sizeof(outrhash));
|
||||||
json_add_u64(response, "msatoshi", outmsatoshi);
|
json_add_u64(response, "msatoshi", outmsatoshi);
|
||||||
json_add_bool(response, "complete", true);
|
json_add_bool(response, "complete", true);
|
||||||
|
json_add_u64(response, "pay_index", outpay_index);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
|
|
||||||
command_success(cmd, response);
|
command_success(cmd, response);
|
||||||
@@ -454,8 +458,8 @@ static void json_waitanyinvoice(struct command *cmd,
|
|||||||
static const struct json_command waitanyinvoice_command = {
|
static const struct json_command waitanyinvoice_command = {
|
||||||
"waitanyinvoice",
|
"waitanyinvoice",
|
||||||
json_waitanyinvoice,
|
json_waitanyinvoice,
|
||||||
"Wait for the next invoice to be paid, after {label} (if supplied)))",
|
"Wait for the next invoice to be paid, after {lastpay_index} (if supplied)))",
|
||||||
"Returns {label}, {rhash} and {msatoshi} on success. "
|
"Returns {label}, {rhash}, {msatoshi}, and {pay_index} on success. "
|
||||||
};
|
};
|
||||||
AUTODATA(json_command, &waitanyinvoice_command);
|
AUTODATA(json_command, &waitanyinvoice_command);
|
||||||
|
|
||||||
|
|||||||
@@ -2435,20 +2435,22 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
l1.rpc.pay(inv2['bolt11'])
|
l1.rpc.pay(inv2['bolt11'])
|
||||||
r = f.result(timeout=5)
|
r = f.result(timeout=5)
|
||||||
assert r['label'] == 'inv1'
|
assert r['label'] == 'inv1'
|
||||||
|
pay_index = r['pay_index']
|
||||||
|
|
||||||
# This one should return immediately with inv2
|
# 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'
|
assert r['label'] == 'inv2'
|
||||||
|
pay_index = r['pay_index']
|
||||||
|
|
||||||
# Now spawn the next waiter
|
# 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)
|
time.sleep(1)
|
||||||
assert not f.done()
|
assert not f.done()
|
||||||
l1.rpc.pay(inv3['bolt11'])
|
l1.rpc.pay(inv3['bolt11'])
|
||||||
r = f.result(timeout=5)
|
r = f.result(timeout=5)
|
||||||
assert r['label'] == 'inv3'
|
assert r['label'] == 'inv3'
|
||||||
|
|
||||||
self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'doesntexist')
|
self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'non-number')
|
||||||
|
|
||||||
|
|
||||||
def test_waitanyinvoice_reversed(self):
|
def test_waitanyinvoice_reversed(self):
|
||||||
@@ -2471,10 +2473,11 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
# Wait - should not block, should return inv2
|
# Wait - should not block, should return inv2
|
||||||
r = self.executor.submit(l2.rpc.waitanyinvoice).result(timeout=5)
|
r = self.executor.submit(l2.rpc.waitanyinvoice).result(timeout=5)
|
||||||
assert r['label'] == 'inv2'
|
assert r['label'] == 'inv2'
|
||||||
|
pay_index = r['pay_index']
|
||||||
# Pay inv1
|
# Pay inv1
|
||||||
l1.rpc.pay(inv1['bolt11'])
|
l1.rpc.pay(inv1['bolt11'])
|
||||||
# Wait inv2 - should not block, should return inv1
|
# 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'
|
assert r['label'] == 'inv1'
|
||||||
|
|
||||||
def test_channel_reenable(self):
|
def test_channel_reenable(self):
|
||||||
|
|||||||
@@ -1125,49 +1125,31 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wallet_invoice_nextpaid(const tal_t *cxt,
|
bool wallet_invoice_nextpaid(const tal_t *cxt,
|
||||||
const struct wallet *wallet,
|
const struct wallet *wallet,
|
||||||
const char *labelz,
|
u64 pay_index,
|
||||||
char **outlabel,
|
char **outlabel,
|
||||||
struct sha256 *outrhash,
|
struct sha256 *outrhash,
|
||||||
u64 *outmsatoshi)
|
u64 *outmsatoshi,
|
||||||
|
u64 *outpay_index)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int res;
|
int res;
|
||||||
u64 pay_index;
|
|
||||||
|
|
||||||
/* Generate query. */
|
/* Generate query. */
|
||||||
if (labelz) {
|
|
||||||
/* Find label. */
|
|
||||||
stmt = db_prepare(wallet->db,
|
stmt = db_prepare(wallet->db,
|
||||||
"SELECT pay_index FROM invoices WHERE label=?;");
|
"SELECT label, payment_hash, msatoshi, pay_index"
|
||||||
sqlite3_bind_text(stmt, 1, labelz, strlen(labelz), SQLITE_TRANSIENT);
|
" FROM invoices"
|
||||||
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"
|
" WHERE pay_index NOT NULL"
|
||||||
" AND pay_index > ?"
|
" AND pay_index > ?"
|
||||||
" ORDER BY pay_index ASC LIMIT 1;");
|
" ORDER BY pay_index ASC LIMIT 1;");
|
||||||
sqlite3_bind_int64(stmt, 1, pay_index);
|
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;");
|
|
||||||
}
|
|
||||||
|
|
||||||
res = sqlite3_step(stmt);
|
res = sqlite3_step(stmt);
|
||||||
if (res != SQLITE_ROW) {
|
if (res != SQLITE_ROW) {
|
||||||
/* No paid invoice found. */
|
/* No paid invoice found. */
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return 0;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
/* Paid invoice found, return data. */
|
/* Paid invoice found, return data. */
|
||||||
*outlabel = tal_strndup(cxt, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
|
*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);
|
*outmsatoshi = sqlite3_column_int64(stmt, 2);
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
*outpay_index = sqlite3_column_int64(stmt, 3);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
sqlite3_finalize(stmt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Acquire the next pay_index. */
|
/* Acquire the next pay_index. */
|
||||||
|
|||||||
@@ -333,28 +333,29 @@ bool wallet_htlcs_reconnect(struct wallet *wallet,
|
|||||||
/**
|
/**
|
||||||
* wallet_invoice_nextpaid -- Find a paid invoice.
|
* wallet_invoice_nextpaid -- Find a paid invoice.
|
||||||
*
|
*
|
||||||
* Get the details (label, rhash, msatoshi) of the next paid
|
* Get the details (label, rhash, msatoshi, pay_index) of the first paid
|
||||||
* invoice after the invoice with the given label. If label is
|
* invoice greater than the given pay_index. Return false if no paid
|
||||||
* `NULL`, get the details of the first paid invoice. Return -1
|
* invoice found, return true if found. The first ever paid invoice will
|
||||||
* if label is non-`NULL` and is not found, 0 if no more paid
|
* have a pay_index of 1 or greater, so giving a pay_index of 0 will get
|
||||||
* invoices after specified invoice (or no paid invoices if label
|
* the first ever paid invoice if there is one.
|
||||||
* is `NULL`), 1 if the next paid invoice was found.
|
|
||||||
*
|
*
|
||||||
* @ctx: Context to create the returned label.
|
* @ctx: Context to create the returned label.
|
||||||
* @wallet: Wallet to query
|
* @wallet: Wallet to query
|
||||||
* @labelz: The label to be queried (zero-terminated), or
|
* @pay_index: The paid invoice returned will have pay_index greater
|
||||||
* `NULL` if first invoice is to be queried.
|
* than this argument.
|
||||||
* @outlabel: Pointer to label of found paid invoice. Caller
|
* @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.
|
* @outrhash: Pointer to struct rhash to be filled.
|
||||||
* @outmsatoshi: Pointer to number of millisatoshis value to pay.
|
* @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,
|
bool wallet_invoice_nextpaid(const tal_t *cxt,
|
||||||
const struct wallet *wallet,
|
const struct wallet *wallet,
|
||||||
const char *labelz,
|
u64 pay_index,
|
||||||
char **outlabel,
|
char **outlabel,
|
||||||
struct sha256 *outrhash,
|
struct sha256 *outrhash,
|
||||||
u64 *outmsatoshi);
|
u64 *outmsatoshi,
|
||||||
|
u64 *outpay_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wallet_invoice_save -- Save/update an invoice to the wallet
|
* wallet_invoice_save -- Save/update an invoice to the wallet
|
||||||
|
|||||||
Reference in New Issue
Block a user