invoices: Remove persistent in-memory invoice structures.
This commit is contained in:
parent
f05c86618c
commit
978e5c67d8
|
@ -62,7 +62,7 @@ static void tell_waiter(struct command *cmd, const struct invoice *inv)
|
|||
struct json_result *response = new_json_result(cmd);
|
||||
struct invoice_details details;
|
||||
|
||||
wallet_invoice_details(cmd, cmd->ld->wallet, inv, &details);
|
||||
wallet_invoice_details(cmd, cmd->ld->wallet, *inv, &details);
|
||||
json_add_invoice(response, &details, true);
|
||||
if (details.state == PAID)
|
||||
command_success(cmd, response);
|
||||
|
@ -104,7 +104,7 @@ static bool hsm_sign_b11(const u5 *u5bytes,
|
|||
static void json_invoice(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
const struct invoice *invoice;
|
||||
struct invoice invoice;
|
||||
struct invoice_details details;
|
||||
jsmntok_t *msatoshi, *label, *desc, *exp, *fallback;
|
||||
u64 *msatoshi_val;
|
||||
|
@ -117,6 +117,7 @@ static void json_invoice(struct command *cmd,
|
|||
char *b11enc;
|
||||
const u8 *fallback_script;
|
||||
u64 expiry = 3600;
|
||||
bool result;
|
||||
|
||||
if (!json_get_params(cmd, buffer, params,
|
||||
"msatoshi", &msatoshi,
|
||||
|
@ -146,7 +147,7 @@ static void json_invoice(struct command *cmd,
|
|||
/* label */
|
||||
label_val = tal_strndup(cmd, buffer + label->start,
|
||||
label->end - label->start);
|
||||
if (wallet_invoice_find_by_label(wallet, label_val)) {
|
||||
if (wallet_invoice_find_by_label(wallet, &invoice, label_val)) {
|
||||
command_fail(cmd, "Duplicate label '%s'", label_val);
|
||||
return;
|
||||
}
|
||||
|
@ -193,11 +194,12 @@ static void json_invoice(struct command *cmd,
|
|||
}
|
||||
|
||||
|
||||
invoice = wallet_invoice_create(cmd->ld->wallet,
|
||||
result = wallet_invoice_create(cmd->ld->wallet,
|
||||
&invoice,
|
||||
take(msatoshi_val),
|
||||
take(label_val),
|
||||
expiry);
|
||||
if (!invoice) {
|
||||
if (!result) {
|
||||
command_fail(cmd, "Failed to create invoice on database");
|
||||
return;
|
||||
}
|
||||
|
@ -318,7 +320,7 @@ AUTODATA(json_command, &listinvoices_command);
|
|||
static void json_delinvoice(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
const struct invoice *i;
|
||||
struct invoice i;
|
||||
struct invoice_details details;
|
||||
jsmntok_t *labeltok, *statustok;
|
||||
struct json_result *response = new_json_result(cmd);
|
||||
|
@ -334,8 +336,7 @@ static void json_delinvoice(struct command *cmd,
|
|||
|
||||
label = tal_strndup(cmd, buffer + labeltok->start,
|
||||
labeltok->end - labeltok->start);
|
||||
i = wallet_invoice_find_by_label(wallet, label);
|
||||
if (!i) {
|
||||
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
|
||||
command_fail(cmd, "Unknown invoice");
|
||||
return;
|
||||
}
|
||||
|
@ -359,7 +360,7 @@ static void json_delinvoice(struct command *cmd,
|
|||
if (!wallet_invoice_delete(wallet, i)) {
|
||||
log_broken(cmd->ld->log,
|
||||
"Error attempting to remove invoice %"PRIu64,
|
||||
i->id);
|
||||
i.id);
|
||||
command_fail(cmd, "Database error");
|
||||
return;
|
||||
}
|
||||
|
@ -424,7 +425,7 @@ AUTODATA(json_command, &waitanyinvoice_command);
|
|||
static void json_waitinvoice(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
const struct invoice *i;
|
||||
struct invoice i;
|
||||
struct invoice_details details;
|
||||
struct wallet *wallet = cmd->ld->wallet;
|
||||
jsmntok_t *labeltok;
|
||||
|
@ -434,18 +435,17 @@ static void json_waitinvoice(struct command *cmd,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Search in paid invoices, if found return immediately */
|
||||
/* Search for invoice */
|
||||
label = tal_strndup(cmd, buffer + labeltok->start, labeltok->end - labeltok->start);
|
||||
i = wallet_invoice_find_by_label(wallet, label);
|
||||
|
||||
if (!i) {
|
||||
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
|
||||
command_fail(cmd, "Label not found");
|
||||
return;
|
||||
}
|
||||
wallet_invoice_details(cmd, cmd->ld->wallet, i, &details);
|
||||
|
||||
/* If paid or expired return immediately */
|
||||
if (details.state == PAID || details.state == EXPIRED) {
|
||||
tell_waiter(cmd, i);
|
||||
tell_waiter(cmd, &i);
|
||||
return;
|
||||
} else {
|
||||
/* There is an unpaid one matching, let's wait... */
|
||||
|
|
|
@ -229,7 +229,7 @@ static void handle_localpay(struct htlc_in *hin,
|
|||
u32 outgoing_cltv_value)
|
||||
{
|
||||
enum onion_type failcode;
|
||||
const struct invoice *invoice;
|
||||
struct invoice invoice;
|
||||
struct invoice_details details;
|
||||
struct lightningd *ld = hin->key.channel->peer->ld;
|
||||
const tal_t *tmpctx = tal_tmpctx(ld);
|
||||
|
@ -262,8 +262,7 @@ static void handle_localpay(struct htlc_in *hin,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
invoice = wallet_invoice_find_unpaid(ld->wallet, payment_hash);
|
||||
if (!invoice) {
|
||||
if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) {
|
||||
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@ struct invoices {
|
|||
struct log *log;
|
||||
/* The timers object to use for expirations. */
|
||||
struct timers *timers;
|
||||
/* The invoice list. */
|
||||
struct list_head invlist;
|
||||
/* Waiters waiting for invoices to be paid, expired, or deleted. */
|
||||
struct list_head waiters;
|
||||
/* Earliest time for some invoice to expire */
|
||||
|
@ -92,37 +90,36 @@ trigger_invoice_waiter_expire_or_delete(struct invoices *invoices,
|
|||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
static bool wallet_stmt2invoice_details(sqlite3_stmt *stmt,
|
||||
struct invoice *invoice,
|
||||
static void wallet_stmt2invoice_details(const tal_t *ctx,
|
||||
sqlite3_stmt *stmt,
|
||||
struct invoice_details *dtl)
|
||||
{
|
||||
invoice->id = sqlite3_column_int64(stmt, 0);
|
||||
dtl->state = sqlite3_column_int(stmt, 1);
|
||||
dtl->state = sqlite3_column_int(stmt, 0);
|
||||
|
||||
assert(sqlite3_column_bytes(stmt, 2) == sizeof(struct preimage));
|
||||
memcpy(&dtl->r, sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2));
|
||||
assert(sqlite3_column_bytes(stmt, 1) == sizeof(struct preimage));
|
||||
memcpy(&dtl->r, sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1));
|
||||
|
||||
assert(sqlite3_column_bytes(stmt, 3) == sizeof(struct sha256));
|
||||
memcpy(&dtl->rhash, sqlite3_column_blob(stmt, 3), sqlite3_column_bytes(stmt, 3));
|
||||
assert(sqlite3_column_bytes(stmt, 2) == sizeof(struct sha256));
|
||||
memcpy(&dtl->rhash, sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2));
|
||||
|
||||
dtl->label = tal_strndup(dtl, sqlite3_column_blob(stmt, 4), sqlite3_column_bytes(stmt, 4));
|
||||
dtl->label = tal_strndup(ctx, sqlite3_column_blob(stmt, 3), sqlite3_column_bytes(stmt, 3));
|
||||
|
||||
if (sqlite3_column_type(stmt, 5) != SQLITE_NULL) {
|
||||
dtl->msatoshi = tal(dtl, u64);
|
||||
*dtl->msatoshi = sqlite3_column_int64(stmt, 5);
|
||||
if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) {
|
||||
dtl->msatoshi = tal(ctx, u64);
|
||||
*dtl->msatoshi = sqlite3_column_int64(stmt, 4);
|
||||
} else {
|
||||
dtl->msatoshi = NULL;
|
||||
}
|
||||
|
||||
dtl->expiry_time = sqlite3_column_int64(stmt, 6);
|
||||
dtl->expiry_time = sqlite3_column_int64(stmt, 5);
|
||||
|
||||
if (dtl->state == PAID) {
|
||||
dtl->pay_index = sqlite3_column_int64(stmt, 7);
|
||||
dtl->msatoshi_received = sqlite3_column_int64(stmt, 8);
|
||||
dtl->paid_timestamp = sqlite3_column_int64(stmt, 9);
|
||||
dtl->pay_index = sqlite3_column_int64(stmt, 6);
|
||||
dtl->msatoshi_received = sqlite3_column_int64(stmt, 7);
|
||||
dtl->paid_timestamp = sqlite3_column_int64(stmt, 8);
|
||||
}
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
struct invoices *invoices_new(const tal_t *ctx,
|
||||
|
@ -136,7 +133,6 @@ struct invoices *invoices_new(const tal_t *ctx,
|
|||
invs->log = log;
|
||||
invs->timers = timers;
|
||||
|
||||
list_head_init(&invs->invlist);
|
||||
list_head_init(&invs->waiters);
|
||||
|
||||
invs->expiration_timer = NULL;
|
||||
|
@ -159,19 +155,6 @@ static void update_db_expirations(struct invoices *invoices, u64 now)
|
|||
db_exec_prepared(invoices->db, stmt);
|
||||
}
|
||||
|
||||
static struct invoice *invoices_find_by_id(struct invoices *invoices,
|
||||
u64 id)
|
||||
{
|
||||
struct invoice *i;
|
||||
|
||||
/* FIXME: Use something better than a linear scan. */
|
||||
list_for_each(&invoices->invlist, i, list) {
|
||||
if (i->id == id)
|
||||
return i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct invoice_id_node {
|
||||
struct list_node list;
|
||||
u64 id;
|
||||
|
@ -185,7 +168,7 @@ static void trigger_expiration(struct invoices *invoices)
|
|||
struct invoice_id_node *idn;
|
||||
u64 now = time_now().ts.tv_sec;
|
||||
sqlite3_stmt *stmt;
|
||||
struct invoice *i;
|
||||
struct invoice i;
|
||||
|
||||
/* Free current expiration timer */
|
||||
invoices->expiration_timer = tal_free(invoices->expiration_timer);
|
||||
|
@ -211,13 +194,11 @@ static void trigger_expiration(struct invoices *invoices)
|
|||
|
||||
/* Trigger expirations */
|
||||
list_for_each(&idlist, idn, list) {
|
||||
/* Update in-memory structure */
|
||||
i = invoices_find_by_id(invoices, idn->id);
|
||||
i->details->state = EXPIRED;
|
||||
/* Trigger expiration */
|
||||
i.id = idn->id;
|
||||
trigger_invoice_waiter_expire_or_delete(invoices,
|
||||
idn->id,
|
||||
i);
|
||||
&i);
|
||||
}
|
||||
|
||||
install_expiration_timer(invoices);
|
||||
|
@ -271,63 +252,34 @@ static void install_expiration_timer(struct invoices *invoices)
|
|||
|
||||
bool invoices_load(struct invoices *invoices)
|
||||
{
|
||||
int count = 0;
|
||||
u64 now = time_now().ts.tv_sec;
|
||||
struct invoice *i;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
update_db_expirations(invoices, now);
|
||||
|
||||
/* Load invoices from db. */
|
||||
stmt = db_query(__func__, invoices->db,
|
||||
"SELECT id, state, payment_key, payment_hash"
|
||||
" , label, msatoshi, expiry_time, pay_index"
|
||||
" , msatoshi_received, paid_timestamp"
|
||||
" FROM invoices;");
|
||||
if (!stmt) {
|
||||
log_broken(invoices->log, "Could not load invoices");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
i = tal(invoices, struct invoice);
|
||||
i->owner = invoices;
|
||||
i->details = tal(i, struct invoice_details);
|
||||
if (!wallet_stmt2invoice_details(stmt, i, i->details)) {
|
||||
log_broken(invoices->log, "Error deserializing invoice");
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
list_add_tail(&invoices->invlist, &i->list);
|
||||
count++;
|
||||
}
|
||||
log_debug(invoices->log, "Loaded %d invoices from DB", count);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
install_expiration_timer(invoices);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct invoice *invoices_create(struct invoices *invoices,
|
||||
bool invoices_create(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
u64 *msatoshi TAKES,
|
||||
const char *label TAKES,
|
||||
u64 expiry)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
struct invoice *invoice;
|
||||
struct invoice dummy;
|
||||
struct preimage r;
|
||||
struct sha256 rhash;
|
||||
u64 expiry_time;
|
||||
u64 now = time_now().ts.tv_sec;
|
||||
|
||||
if (invoices_find_by_label(invoices, label)) {
|
||||
if (invoices_find_by_label(invoices, &dummy, label)) {
|
||||
if (taken(msatoshi))
|
||||
tal_free(msatoshi);
|
||||
if (taken(label))
|
||||
tal_free(label);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compute expiration. */
|
||||
|
@ -363,21 +315,7 @@ const struct invoice *invoices_create(struct invoices *invoices,
|
|||
|
||||
db_exec_prepared(invoices->db, stmt);
|
||||
|
||||
/* Create and load in-memory structure. */
|
||||
invoice = tal(invoices, struct invoice);
|
||||
invoice->owner = invoices;
|
||||
|
||||
invoice->id = sqlite3_last_insert_rowid(invoices->db->sql);
|
||||
invoice->details = tal(invoice, struct invoice_details);
|
||||
invoice->details->state = UNPAID;
|
||||
invoice->details->label = tal_strdup(invoice->details, label);
|
||||
invoice->details->msatoshi = tal_dup(invoice->details, u64, msatoshi); /* Works even if msatoshi == NULL. */
|
||||
memcpy(&invoice->details->r, &r, sizeof(invoice->details->r));
|
||||
memcpy(&invoice->details->rhash, &rhash, sizeof(invoice->details->rhash));
|
||||
invoice->details->expiry_time = expiry_time;
|
||||
|
||||
/* Add to invoices object. */
|
||||
list_add_tail(&invoices->invlist, &invoice->list);
|
||||
pinvoice->id = sqlite3_last_insert_rowid(invoices->db->sql);
|
||||
|
||||
/* Install expiration trigger. */
|
||||
if (!invoices->expiration_timer ||
|
||||
|
@ -387,80 +325,109 @@ const struct invoice *invoices_create(struct invoices *invoices,
|
|||
install_expiration_timer(invoices);
|
||||
}
|
||||
|
||||
return invoice;
|
||||
if (taken(msatoshi))
|
||||
tal_free(msatoshi);
|
||||
if (taken(label))
|
||||
tal_free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const struct invoice *invoices_find_by_label(struct invoices *invoices,
|
||||
bool invoices_find_by_label(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
const char *label)
|
||||
{
|
||||
struct invoice *i;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
/* FIXME: Use something better than a linear scan. */
|
||||
list_for_each(&invoices->invlist, i, list) {
|
||||
if (streq(i->details->label, label))
|
||||
return i;
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT id"
|
||||
" FROM invoices"
|
||||
" WHERE label = ?;");
|
||||
sqlite3_bind_text(stmt, 1, label, strlen(label), SQLITE_TRANSIENT);
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
pinvoice->id = sqlite3_column_int64(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
return true;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct invoice *invoices_find_unpaid(struct invoices *invoices,
|
||||
bool invoices_find_unpaid(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
const struct sha256 *rhash)
|
||||
{
|
||||
struct invoice *i;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
list_for_each(&invoices->invlist, i, list) {
|
||||
if (structeq(rhash, &i->details->rhash) &&
|
||||
i->details->state == UNPAID) {
|
||||
if (time_now().ts.tv_sec > i->details->expiry_time)
|
||||
break;
|
||||
return i;
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT id"
|
||||
" FROM invoices"
|
||||
" WHERE payment_hash = ?"
|
||||
" AND state = ?;");
|
||||
sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int(stmt, 2, UNPAID);
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
pinvoice->id = sqlite3_column_int64(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
return true;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool invoices_delete(struct invoices *invoices,
|
||||
const struct invoice *cinvoice)
|
||||
struct invoice invoice)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
struct invoice *invoice = (struct invoice *) cinvoice;
|
||||
|
||||
/* Delete from database. */
|
||||
stmt = db_prepare(invoices->db, "DELETE FROM invoices WHERE id=?;");
|
||||
sqlite3_bind_int64(stmt, 1, invoice->id);
|
||||
sqlite3_bind_int64(stmt, 1, invoice.id);
|
||||
db_exec_prepared(invoices->db, stmt);
|
||||
|
||||
if (sqlite3_changes(invoices->db->sql) != 1)
|
||||
return false;
|
||||
|
||||
/* Delete from invoices object. */
|
||||
list_del_from(&invoices->invlist, &invoice->list);
|
||||
|
||||
/* Tell all the waiters about the fact that it was deleted. */
|
||||
trigger_invoice_waiter_expire_or_delete(invoices,
|
||||
invoice->id, NULL);
|
||||
|
||||
/* Free all watchers and the invoice. */
|
||||
tal_free(invoice);
|
||||
invoice.id, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool invoices_iterate(struct invoices *invoices,
|
||||
struct invoice_iterator *it)
|
||||
{
|
||||
if (it->curr)
|
||||
it->curr = list_next(&invoices->invlist, it->curr, list);
|
||||
else
|
||||
it->curr = list_top(&invoices->invlist, struct invoice, list);
|
||||
return it->curr != NULL;
|
||||
sqlite3_stmt *stmt;
|
||||
int res;
|
||||
if (!it->p) {
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT state, payment_key, payment_hash"
|
||||
" , label, msatoshi, expiry_time, pay_index"
|
||||
" , msatoshi_received, paid_timestamp"
|
||||
" FROM invoices;");
|
||||
it->p = stmt;
|
||||
} else
|
||||
stmt = it->p;
|
||||
|
||||
res = sqlite3_step(stmt);
|
||||
if (res == SQLITE_DONE) {
|
||||
sqlite3_finalize(stmt);
|
||||
it->p = NULL;
|
||||
return false;
|
||||
} else {
|
||||
assert(res == SQLITE_ROW);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void invoices_iterator_deref(const tal_t *ctx,
|
||||
struct invoices *invoices,
|
||||
const struct invoice_iterator *it,
|
||||
struct invoice_details *details)
|
||||
{
|
||||
invoices_get_details(ctx, invoices, it->curr, details);
|
||||
assert(it->p);
|
||||
wallet_stmt2invoice_details(ctx, (sqlite3_stmt*) it->p, details);
|
||||
}
|
||||
|
||||
static s64 get_next_pay_index(struct db *db)
|
||||
|
@ -476,11 +443,10 @@ static s64 get_next_pay_index(struct db *db)
|
|||
|
||||
|
||||
void invoices_resolve(struct invoices *invoices,
|
||||
const struct invoice *cinvoice,
|
||||
struct invoice invoice,
|
||||
u64 msatoshi_received)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
struct invoice *invoice = (struct invoice *)cinvoice;
|
||||
s64 pay_index;
|
||||
u64 paid_timestamp;
|
||||
const tal_t *tmpctx = tal_tmpctx(NULL);
|
||||
|
@ -501,17 +467,11 @@ void invoices_resolve(struct invoices *invoices,
|
|||
sqlite3_bind_int64(stmt, 2, pay_index);
|
||||
sqlite3_bind_int64(stmt, 3, msatoshi_received);
|
||||
sqlite3_bind_int64(stmt, 4, paid_timestamp);
|
||||
sqlite3_bind_int64(stmt, 5, invoice->id);
|
||||
sqlite3_bind_int64(stmt, 5, invoice.id);
|
||||
db_exec_prepared(invoices->db, stmt);
|
||||
|
||||
/* Update in-memory structure. */
|
||||
invoice->details->state = PAID;
|
||||
invoice->details->pay_index = pay_index;
|
||||
invoice->details->msatoshi_received = msatoshi_received;
|
||||
invoice->details->paid_timestamp = paid_timestamp;
|
||||
|
||||
/* Tell all the waiters about the paid invoice. */
|
||||
trigger_invoice_waiter_resolve(invoices, invoice->id, invoice);
|
||||
trigger_invoice_waiter_resolve(invoices, invoice.id, &invoice);
|
||||
|
||||
/* Free all watchers. */
|
||||
tal_free(tmpctx);
|
||||
|
@ -552,13 +512,12 @@ void invoices_waitany(const tal_t *ctx,
|
|||
void *cbarg)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
const struct invoice *invoice;
|
||||
struct invoice invoice;
|
||||
int res;
|
||||
char const* label;
|
||||
|
||||
/* Look for an already-paid invoice. */
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT label"
|
||||
"SELECT id"
|
||||
" FROM invoices"
|
||||
" WHERE pay_index NOT NULL"
|
||||
" AND pay_index > ?"
|
||||
|
@ -567,16 +526,10 @@ void invoices_waitany(const tal_t *ctx,
|
|||
|
||||
res = sqlite3_step(stmt);
|
||||
if (res == SQLITE_ROW) {
|
||||
/* Invoice found. Look up the invoice object. */
|
||||
label = tal_strndup(ctx, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
|
||||
invoice.id = sqlite3_column_int64(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
/* The invoice should definitely exist in-memory. */
|
||||
invoice = invoices_find_by_label(invoices, label);
|
||||
assert(invoice);
|
||||
tal_free(label);
|
||||
|
||||
cb(invoice, cbarg);
|
||||
cb(&invoice, cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -590,38 +543,53 @@ void invoices_waitany(const tal_t *ctx,
|
|||
|
||||
void invoices_waitone(const tal_t *ctx,
|
||||
struct invoices *invoices UNUSED,
|
||||
struct invoice const *cinvoice,
|
||||
struct invoice invoice,
|
||||
void (*cb)(const struct invoice *, void*),
|
||||
void *cbarg)
|
||||
{
|
||||
struct invoice *invoice = (struct invoice*) cinvoice;
|
||||
if (invoice->details->state == PAID || invoice->details->state == EXPIRED) {
|
||||
cb(invoice, cbarg);
|
||||
sqlite3_stmt *stmt;
|
||||
int res;
|
||||
enum invoice_status state;
|
||||
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT state"
|
||||
" FROM invoices"
|
||||
" WHERE id = ?;");
|
||||
sqlite3_bind_int64(stmt, 1, invoice.id);
|
||||
res = sqlite3_step(stmt);
|
||||
assert(res == SQLITE_ROW);
|
||||
state = sqlite3_column_int(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (state == PAID || state == EXPIRED) {
|
||||
cb(&invoice, cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not yet paid. */
|
||||
add_invoice_waiter(ctx, &invoices->waiters,
|
||||
false, invoice->id, cb, cbarg);
|
||||
false, invoice.id, cb, cbarg);
|
||||
}
|
||||
|
||||
void invoices_get_details(const tal_t *ctx,
|
||||
struct invoices *invoices,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
struct invoice_details *dtl)
|
||||
{
|
||||
dtl->state = invoice->details->state;
|
||||
dtl->r = invoice->details->r;
|
||||
dtl->rhash = invoice->details->rhash;
|
||||
dtl->label = tal_strdup(ctx, invoice->details->label);
|
||||
dtl->msatoshi =
|
||||
invoice->details->msatoshi ?
|
||||
tal_dup(ctx, u64, invoice->details->msatoshi) :
|
||||
/*otherwise*/ NULL ;
|
||||
dtl->expiry_time = invoice->details->expiry_time;
|
||||
if (dtl->state == PAID) {
|
||||
dtl->pay_index = invoice->details->pay_index;
|
||||
dtl->msatoshi_received = invoice->details->msatoshi_received;
|
||||
dtl->paid_timestamp = invoice->details->paid_timestamp;
|
||||
}
|
||||
sqlite3_stmt *stmt;
|
||||
int result;
|
||||
|
||||
stmt = db_prepare(invoices->db,
|
||||
"SELECT state, payment_key, payment_hash"
|
||||
" , label, msatoshi, expiry_time, pay_index"
|
||||
" , msatoshi_received, paid_timestamp"
|
||||
" FROM invoices"
|
||||
" WHERE id = ?;");
|
||||
sqlite3_bind_int64(stmt, 1, invoice.id);
|
||||
result = sqlite3_step(stmt);
|
||||
assert(result == SQLITE_ROW);
|
||||
|
||||
wallet_stmt2invoice_details(ctx, stmt, dtl);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ bool invoices_load(struct invoices *invoices);
|
|||
* invoices_create - Create a new invoice.
|
||||
*
|
||||
* @invoices - the invoice handler.
|
||||
* @pinvoice - pointer to location to load new invoice in.
|
||||
* @msatoshi - the amount the invoice should have, or
|
||||
* NULL for any-amount invoices.
|
||||
* @label - the unique label for this invoice. Must be
|
||||
|
@ -46,10 +47,12 @@ bool invoices_load(struct invoices *invoices);
|
|||
* @expiry - the number of seconds before the invoice
|
||||
* expires
|
||||
*
|
||||
* Returns NULL if label already exists or expiry is 0.
|
||||
* Returns false if label already exists or expiry is 0.
|
||||
* Returns true if created invoice.
|
||||
* FIXME: Fallback addresses
|
||||
*/
|
||||
const struct invoice *invoices_create(struct invoices *invoices,
|
||||
bool invoices_create(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
u64 *msatoshi TAKES,
|
||||
const char *label TAKES,
|
||||
u64 expiry);
|
||||
|
@ -58,11 +61,14 @@ const struct invoice *invoices_create(struct invoices *invoices,
|
|||
* invoices_find_by_label - Search for an invoice by label
|
||||
*
|
||||
* @invoices - the invoice handler.
|
||||
* @pinvoice - pointer to location to load found invoice in.
|
||||
* @label - the label to search for. Must be null-terminated.
|
||||
*
|
||||
* Returns NULL if no invoice with that label exists.
|
||||
* Returns false if no invoice with that label exists.
|
||||
* Returns true if found.
|
||||
*/
|
||||
const struct invoice *invoices_find_by_label(struct invoices *invoices,
|
||||
bool invoices_find_by_label(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
|
@ -70,11 +76,14 @@ const struct invoice *invoices_find_by_label(struct invoices *invoices,
|
|||
* payment_hash
|
||||
*
|
||||
* @invoices - the invoice handler.
|
||||
* @pinvoice - pointer to location to load found invoice in.
|
||||
* @rhash - the payment_hash to search for.
|
||||
*
|
||||
* Returns NULL if no invoice with that payment hash exists.
|
||||
* Returns false if no unpaid invoice with that rhash exists.
|
||||
* Returns true if found.
|
||||
*/
|
||||
const struct invoice *invoices_find_unpaid(struct invoices *invoices,
|
||||
bool invoices_find_unpaid(struct invoices *invoices,
|
||||
struct invoice *pinvoice,
|
||||
const struct sha256 *rhash);
|
||||
|
||||
/**
|
||||
|
@ -86,7 +95,7 @@ const struct invoice *invoices_find_unpaid(struct invoices *invoices,
|
|||
* Return false on failure.
|
||||
*/
|
||||
bool invoices_delete(struct invoices *invoices,
|
||||
const struct invoice *invoice);
|
||||
struct invoice invoice);
|
||||
|
||||
/**
|
||||
* invoices_iterate - Iterate over all existing invoices
|
||||
|
@ -132,7 +141,7 @@ void invoices_iterator_deref(const tal_t *ctx,
|
|||
* does not check).
|
||||
*/
|
||||
void invoices_resolve(struct invoices *invoices,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
u64 msatoshi_received);
|
||||
|
||||
/**
|
||||
|
@ -173,7 +182,7 @@ void invoices_waitany(const tal_t *ctx,
|
|||
*/
|
||||
void invoices_waitone(const tal_t *ctx,
|
||||
struct invoices *invoices,
|
||||
struct invoice const *invoice,
|
||||
struct invoice invoice,
|
||||
void (*cb)(const struct invoice *, void*),
|
||||
void *cbarg);
|
||||
|
||||
|
@ -187,7 +196,7 @@ void invoices_waitone(const tal_t *ctx,
|
|||
*/
|
||||
void invoices_get_details(const tal_t *ctx,
|
||||
struct invoices *invoices,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
struct invoice_details *details);
|
||||
|
||||
#endif /* LIGHTNING_WALLET_INVOICES_H */
|
||||
|
|
|
@ -95,27 +95,30 @@ u8 *get_supported_global_features(const tal_t *ctx UNNEEDED)
|
|||
u8 *get_supported_local_features(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "get_supported_local_features called!\n"); abort(); }
|
||||
/* Generated stub for invoices_create */
|
||||
const struct invoice *invoices_create(struct invoices *invoices UNNEEDED,
|
||||
bool invoices_create(struct invoices *invoices UNNEEDED,
|
||||
struct invoice *pinvoice UNNEEDED,
|
||||
u64 *msatoshi TAKES UNNEEDED,
|
||||
const char *label TAKES UNNEEDED,
|
||||
u64 expiry UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_create called!\n"); abort(); }
|
||||
/* Generated stub for invoices_delete */
|
||||
bool invoices_delete(struct invoices *invoices UNNEEDED,
|
||||
const struct invoice *invoice UNNEEDED)
|
||||
struct invoice invoice UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_delete called!\n"); abort(); }
|
||||
/* Generated stub for invoices_find_by_label */
|
||||
const struct invoice *invoices_find_by_label(struct invoices *invoices UNNEEDED,
|
||||
bool invoices_find_by_label(struct invoices *invoices UNNEEDED,
|
||||
struct invoice *pinvoice UNNEEDED,
|
||||
const char *label UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_find_by_label called!\n"); abort(); }
|
||||
/* Generated stub for invoices_find_unpaid */
|
||||
const struct invoice *invoices_find_unpaid(struct invoices *invoices UNNEEDED,
|
||||
bool invoices_find_unpaid(struct invoices *invoices UNNEEDED,
|
||||
struct invoice *pinvoice UNNEEDED,
|
||||
const struct sha256 *rhash UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_find_unpaid called!\n"); abort(); }
|
||||
/* Generated stub for invoices_get_details */
|
||||
void invoices_get_details(const tal_t *ctx UNNEEDED,
|
||||
struct invoices *invoices UNNEEDED,
|
||||
const struct invoice *invoice UNNEEDED,
|
||||
struct invoice invoice UNNEEDED,
|
||||
struct invoice_details *details UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_get_details called!\n"); abort(); }
|
||||
/* Generated stub for invoices_iterate */
|
||||
|
@ -139,7 +142,7 @@ struct invoices *invoices_new(const tal_t *ctx UNNEEDED,
|
|||
{ fprintf(stderr, "invoices_new called!\n"); abort(); }
|
||||
/* Generated stub for invoices_resolve */
|
||||
void invoices_resolve(struct invoices *invoices UNNEEDED,
|
||||
const struct invoice *invoice UNNEEDED,
|
||||
struct invoice invoice UNNEEDED,
|
||||
u64 msatoshi_received UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_resolve called!\n"); abort(); }
|
||||
/* Generated stub for invoices_waitany */
|
||||
|
@ -152,7 +155,7 @@ void invoices_waitany(const tal_t *ctx UNNEEDED,
|
|||
/* Generated stub for invoices_waitone */
|
||||
void invoices_waitone(const tal_t *ctx UNNEEDED,
|
||||
struct invoices *invoices UNNEEDED,
|
||||
struct invoice const *invoice UNNEEDED,
|
||||
struct invoice invoice UNNEEDED,
|
||||
void (*cb)(const struct invoice * UNNEEDED, void*) UNNEEDED,
|
||||
void *cbarg UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_waitone called!\n"); abort(); }
|
||||
|
|
|
@ -1266,24 +1266,27 @@ bool wallet_invoice_load(struct wallet *wallet)
|
|||
{
|
||||
return invoices_load(wallet->invoices);
|
||||
}
|
||||
const struct invoice *wallet_invoice_create(struct wallet *wallet,
|
||||
bool wallet_invoice_create(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
u64 *msatoshi TAKES,
|
||||
const char *label TAKES,
|
||||
u64 expiry) {
|
||||
return invoices_create(wallet->invoices, msatoshi, label, expiry);
|
||||
return invoices_create(wallet->invoices, pinvoice, msatoshi, label, expiry);
|
||||
}
|
||||
const struct invoice *wallet_invoice_find_by_label(struct wallet *wallet,
|
||||
bool wallet_invoice_find_by_label(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
const char *label)
|
||||
{
|
||||
return invoices_find_by_label(wallet->invoices, label);
|
||||
return invoices_find_by_label(wallet->invoices, pinvoice, label);
|
||||
}
|
||||
const struct invoice *wallet_invoice_find_unpaid(struct wallet *wallet,
|
||||
bool wallet_invoice_find_unpaid(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
const struct sha256 *rhash)
|
||||
{
|
||||
return invoices_find_unpaid(wallet->invoices, rhash);
|
||||
return invoices_find_unpaid(wallet->invoices, pinvoice, rhash);
|
||||
}
|
||||
bool wallet_invoice_delete(struct wallet *wallet,
|
||||
const struct invoice *invoice)
|
||||
struct invoice invoice)
|
||||
{
|
||||
return invoices_delete(wallet->invoices, invoice);
|
||||
}
|
||||
|
@ -1300,7 +1303,7 @@ void wallet_invoice_iterator_deref(const tal_t *ctx,
|
|||
return invoices_iterator_deref(ctx, wallet->invoices, it, details);
|
||||
}
|
||||
void wallet_invoice_resolve(struct wallet *wallet,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
u64 msatoshi_received)
|
||||
{
|
||||
invoices_resolve(wallet->invoices, invoice, msatoshi_received);
|
||||
|
@ -1315,7 +1318,7 @@ void wallet_invoice_waitany(const tal_t *ctx,
|
|||
}
|
||||
void wallet_invoice_waitone(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
struct invoice const *invoice,
|
||||
struct invoice invoice,
|
||||
void (*cb)(const struct invoice *, void*),
|
||||
void *cbarg)
|
||||
{
|
||||
|
@ -1323,7 +1326,7 @@ void wallet_invoice_waitone(const tal_t *ctx,
|
|||
}
|
||||
void wallet_invoice_details(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
struct invoice_details *details)
|
||||
{
|
||||
invoices_get_details(ctx, wallet->invoices, invoice, details);
|
||||
|
|
|
@ -394,20 +394,13 @@ struct invoice_details {
|
|||
struct invoice_iterator {
|
||||
/* The contents of this object is subject to change
|
||||
* and should not be depended upon */
|
||||
const struct invoice *curr;
|
||||
void *p;
|
||||
};
|
||||
|
||||
struct invoice {
|
||||
/* Internal, rest of lightningd should not use */
|
||||
/* List off ld->wallet->invoices. Must be first or else
|
||||
* dev-memleak is driven insane. */
|
||||
struct list_node list;
|
||||
/* Database ID */
|
||||
u64 id;
|
||||
/* The owning invoices object. */
|
||||
struct invoices *owner;
|
||||
/* Loaded details. */
|
||||
struct invoice_details *details;
|
||||
};
|
||||
|
||||
#define INVOICE_MAX_LABEL_LEN 128
|
||||
|
@ -430,6 +423,7 @@ bool wallet_invoice_load(struct wallet *wallet);
|
|||
* wallet_invoice_create - Create a new invoice.
|
||||
*
|
||||
* @wallet - the wallet to create the invoice in.
|
||||
* @pinvoice - pointer to location to load new invoice in.
|
||||
* @msatoshi - the amount the invoice should have, or
|
||||
* NULL for any-amount invoices.
|
||||
* @label - the unique label for this invoice. Must be
|
||||
|
@ -437,10 +431,12 @@ bool wallet_invoice_load(struct wallet *wallet);
|
|||
* @expiry - the number of seconds before the invoice
|
||||
* expires
|
||||
*
|
||||
* Returns NULL if label already exists or expiry is 0.
|
||||
* Returns false if label already exists or expiry is 0.
|
||||
* Returns true if created invoice.
|
||||
* FIXME: Fallback addresses
|
||||
*/
|
||||
const struct invoice *wallet_invoice_create(struct wallet *wallet,
|
||||
bool wallet_invoice_create(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
u64 *msatoshi TAKES,
|
||||
const char *label TAKES,
|
||||
u64 expiry);
|
||||
|
@ -449,11 +445,14 @@ const struct invoice *wallet_invoice_create(struct wallet *wallet,
|
|||
* wallet_invoice_find_by_label - Search for an invoice by label
|
||||
*
|
||||
* @wallet - the wallet to search.
|
||||
* @pinvoice - pointer to location to load found invoice in.
|
||||
* @label - the label to search for. Must be null-terminated.
|
||||
*
|
||||
* Returns NULL if no invoice with that label exists.
|
||||
* Returns false if no invoice with that label exists.
|
||||
* Returns true if found.
|
||||
*/
|
||||
const struct invoice *wallet_invoice_find_by_label(struct wallet *wallet,
|
||||
bool wallet_invoice_find_by_label(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
|
@ -461,11 +460,14 @@ const struct invoice *wallet_invoice_find_by_label(struct wallet *wallet,
|
|||
* payment_hash
|
||||
*
|
||||
* @wallet - the wallet to search.
|
||||
* @pinvoice - pointer to location to load found invoice in.
|
||||
* @rhash - the payment_hash to search for.
|
||||
*
|
||||
* Returns NULL if no invoice with that payment hash exists.
|
||||
* Returns false if no unpaid invoice with that rhash exists.
|
||||
* Returns true if found.
|
||||
*/
|
||||
const struct invoice *wallet_invoice_find_unpaid(struct wallet *wallet,
|
||||
bool wallet_invoice_find_unpaid(struct wallet *wallet,
|
||||
struct invoice *pinvoice,
|
||||
const struct sha256 *rhash);
|
||||
|
||||
/**
|
||||
|
@ -477,7 +479,7 @@ const struct invoice *wallet_invoice_find_unpaid(struct wallet *wallet,
|
|||
* Return false on failure.
|
||||
*/
|
||||
bool wallet_invoice_delete(struct wallet *wallet,
|
||||
const struct invoice *invoice);
|
||||
struct invoice invoice);
|
||||
|
||||
/**
|
||||
* wallet_invoice_iterate - Iterate over all existing invoices
|
||||
|
@ -520,10 +522,10 @@ void wallet_invoice_iterator_deref(const tal_t *ctx,
|
|||
* @msatoshi_received - the actual amount received.
|
||||
*
|
||||
* Precondition: the invoice must not yet be expired (wallet
|
||||
* does not check).
|
||||
* does not check!).
|
||||
*/
|
||||
void wallet_invoice_resolve(struct wallet *wallet,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
u64 msatoshi_received);
|
||||
|
||||
/**
|
||||
|
@ -537,7 +539,8 @@ void wallet_invoice_resolve(struct wallet *wallet,
|
|||
* @cb - the callback to invoke. If an invoice is already
|
||||
* paid with pay_index greater than lastpay_index, this
|
||||
* is called immediately, otherwise it is called during
|
||||
* an invoices_resolve call.
|
||||
* an invoices_resolve call. Will never be given a NULL
|
||||
* pointer-to-invoice.
|
||||
* @cbarg - the callback data.
|
||||
*/
|
||||
void wallet_invoice_waitany(const tal_t *ctx,
|
||||
|
@ -564,7 +567,7 @@ void wallet_invoice_waitany(const tal_t *ctx,
|
|||
*/
|
||||
void wallet_invoice_waitone(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
struct invoice const *invoice,
|
||||
struct invoice invoice,
|
||||
void (*cb)(const struct invoice *, void*),
|
||||
void *cbarg);
|
||||
|
||||
|
@ -578,7 +581,7 @@ void wallet_invoice_waitone(const tal_t *ctx,
|
|||
*/
|
||||
void wallet_invoice_details(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
const struct invoice *invoice,
|
||||
struct invoice invoice,
|
||||
struct invoice_details *details);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue