mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 07:34:24 +01:00
invoice: fix potential race where invoice is paid/expired while we're calling hook.
There's actually a (very unlikely) race here: we would previously have crashed with an assertion in invoices_resolve. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -250,11 +250,17 @@ invoice_payment_hooks_done(struct invoice_payment_hook_payload *payload STEALS)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Paid or expired in the meantime. */
|
||||||
|
if (!wallet_invoice_resolve(ld->wallet, invoice, payload->msat)) {
|
||||||
|
htlc_set_fail(payload->set, take(failmsg_incorrect_or_unknown(
|
||||||
|
NULL, ld, payload->set->htlcs[0])));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log_info(ld->log, "Resolved invoice '%s' with amount %s in %zu htlcs",
|
log_info(ld->log, "Resolved invoice '%s' with amount %s in %zu htlcs",
|
||||||
payload->label->s,
|
payload->label->s,
|
||||||
type_to_string(tmpctx, struct amount_msat, &payload->msat),
|
type_to_string(tmpctx, struct amount_msat, &payload->msat),
|
||||||
tal_count(payload->set->htlcs));
|
tal_count(payload->set->htlcs));
|
||||||
wallet_invoice_resolve(ld->wallet, invoice, payload->msat);
|
|
||||||
htlc_set_fulfill(payload->set, &payload->preimage);
|
htlc_set_fulfill(payload->set, &payload->preimage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ const struct invoice_details *wallet_invoice_iterator_deref(const tal_t *ctx UNN
|
|||||||
const struct invoice_iterator *it UNNEEDED)
|
const struct invoice_iterator *it UNNEEDED)
|
||||||
{ fprintf(stderr, "wallet_invoice_iterator_deref called!\n"); abort(); }
|
{ fprintf(stderr, "wallet_invoice_iterator_deref called!\n"); abort(); }
|
||||||
/* Generated stub for wallet_invoice_resolve */
|
/* Generated stub for wallet_invoice_resolve */
|
||||||
void wallet_invoice_resolve(struct wallet *wallet UNNEEDED,
|
bool wallet_invoice_resolve(struct wallet *wallet UNNEEDED,
|
||||||
struct invoice invoice UNNEEDED,
|
struct invoice invoice UNNEEDED,
|
||||||
struct amount_msat received UNNEEDED)
|
struct amount_msat received UNNEEDED)
|
||||||
{ fprintf(stderr, "wallet_invoice_resolve called!\n"); abort(); }
|
{ fprintf(stderr, "wallet_invoice_resolve called!\n"); abort(); }
|
||||||
|
|||||||
2
wallet/db_postgres_sqlgen.c
generated
2
wallet/db_postgres_sqlgen.c
generated
@@ -1690,4 +1690,4 @@ struct db_query db_postgres_queries[] = {
|
|||||||
|
|
||||||
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
|
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
|
||||||
|
|
||||||
// SHA256STAMP:a61b8b6ea86287e22c696530a9b5cd35ccef271280b8ac34d2665dc5aff42fce
|
// SHA256STAMP:fac2fa6846e0deadf6f24fc9deb6efb0bac04b5947c254ae39300663366178af
|
||||||
|
|||||||
2
wallet/db_sqlite3_sqlgen.c
generated
2
wallet/db_sqlite3_sqlgen.c
generated
@@ -1690,4 +1690,4 @@ struct db_query db_sqlite3_queries[] = {
|
|||||||
|
|
||||||
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
|
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
|
||||||
|
|
||||||
// SHA256STAMP:a61b8b6ea86287e22c696530a9b5cd35ccef271280b8ac34d2665dc5aff42fce
|
// SHA256STAMP:fac2fa6846e0deadf6f24fc9deb6efb0bac04b5947c254ae39300663366178af
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ static enum invoice_status invoice_get_status(struct invoices *invoices, struct
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void invoices_resolve(struct invoices *invoices,
|
bool invoices_resolve(struct invoices *invoices,
|
||||||
struct invoice invoice,
|
struct invoice invoice,
|
||||||
struct amount_msat received)
|
struct amount_msat received)
|
||||||
{
|
{
|
||||||
@@ -505,7 +505,8 @@ void invoices_resolve(struct invoices *invoices,
|
|||||||
u64 paid_timestamp;
|
u64 paid_timestamp;
|
||||||
enum invoice_status state = invoice_get_status(invoices, invoice);
|
enum invoice_status state = invoice_get_status(invoices, invoice);
|
||||||
|
|
||||||
assert(state == UNPAID);
|
if (state != UNPAID)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* Assign a pay-index. */
|
/* Assign a pay-index. */
|
||||||
pay_index = get_next_pay_index(invoices->db);
|
pay_index = get_next_pay_index(invoices->db);
|
||||||
@@ -527,6 +528,7 @@ void invoices_resolve(struct invoices *invoices,
|
|||||||
|
|
||||||
/* Tell all the waiters about the paid invoice. */
|
/* Tell all the waiters about the paid invoice. */
|
||||||
trigger_invoice_waiter_resolve(invoices, invoice.id, &invoice);
|
trigger_invoice_waiter_resolve(invoices, invoice.id, &invoice);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when an invoice waiter is destructed. */
|
/* Called when an invoice waiter is destructed. */
|
||||||
|
|||||||
@@ -174,10 +174,9 @@ const struct invoice_details *invoices_iterator_deref(
|
|||||||
* @invoice - the invoice to mark as paid.
|
* @invoice - the invoice to mark as paid.
|
||||||
* @received - the actual amount received.
|
* @received - the actual amount received.
|
||||||
*
|
*
|
||||||
* Precondition: the invoice must not yet be expired (invoices
|
* If the invoice is not UNPAID, returns false.
|
||||||
* does not check).
|
|
||||||
*/
|
*/
|
||||||
void invoices_resolve(struct invoices *invoices,
|
bool invoices_resolve(struct invoices *invoices,
|
||||||
struct invoice invoice,
|
struct invoice invoice,
|
||||||
struct amount_msat received);
|
struct amount_msat received);
|
||||||
|
|
||||||
|
|||||||
8
wallet/statements_gettextgen.po
generated
8
wallet/statements_gettextgen.po
generated
@@ -666,15 +666,15 @@ msgstr ""
|
|||||||
msgid "SELECT state FROM invoices WHERE id = ?;"
|
msgid "SELECT state FROM invoices WHERE id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/invoices.c:515
|
#: wallet/invoices.c:516
|
||||||
msgid "UPDATE invoices SET state=? , pay_index=? , msatoshi_received=? , paid_timestamp=? WHERE id=?;"
|
msgid "UPDATE invoices SET state=? , pay_index=? , msatoshi_received=? , paid_timestamp=? WHERE id=?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/invoices.c:571
|
#: wallet/invoices.c:573
|
||||||
msgid "SELECT id FROM invoices WHERE pay_index IS NOT NULL AND pay_index > ? ORDER BY pay_index ASC LIMIT 1;"
|
msgid "SELECT id FROM invoices WHERE pay_index IS NOT NULL AND pay_index > ? ORDER BY pay_index ASC LIMIT 1;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/invoices.c:620
|
#: wallet/invoices.c:622
|
||||||
msgid "SELECT state, payment_key, payment_hash, label, msatoshi, expiry_time, pay_index, msatoshi_received, paid_timestamp, bolt11, description, features FROM invoices WHERE id = ?;"
|
msgid "SELECT state, payment_key, payment_hash, label, msatoshi, expiry_time, pay_index, msatoshi_received, paid_timestamp, bolt11, description, features FROM invoices WHERE id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1113,4 +1113,4 @@ msgstr ""
|
|||||||
#: wallet/test/run-wallet.c:1376
|
#: wallet/test/run-wallet.c:1376
|
||||||
msgid "INSERT INTO channels (id) VALUES (1);"
|
msgid "INSERT INTO channels (id) VALUES (1);"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
# SHA256STAMP:a63bd31a3977b161d8245ffddf5de3a03c972a60436eb8cbc1bb23f0ffb03405
|
# SHA256STAMP:8f226711a58166b481aaa7b8c0593c7159711bee623737e3b4750f6c154d4f65
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ struct invoices *invoices_new(const tal_t *ctx UNNEEDED,
|
|||||||
struct timers *timers UNNEEDED)
|
struct timers *timers UNNEEDED)
|
||||||
{ fprintf(stderr, "invoices_new called!\n"); abort(); }
|
{ fprintf(stderr, "invoices_new called!\n"); abort(); }
|
||||||
/* Generated stub for invoices_resolve */
|
/* Generated stub for invoices_resolve */
|
||||||
void invoices_resolve(struct invoices *invoices UNNEEDED,
|
bool invoices_resolve(struct invoices *invoices UNNEEDED,
|
||||||
struct invoice invoice UNNEEDED,
|
struct invoice invoice UNNEEDED,
|
||||||
struct amount_msat received UNNEEDED)
|
struct amount_msat received UNNEEDED)
|
||||||
{ fprintf(stderr, "invoices_resolve called!\n"); abort(); }
|
{ fprintf(stderr, "invoices_resolve called!\n"); abort(); }
|
||||||
|
|||||||
@@ -2337,11 +2337,11 @@ wallet_invoice_iterator_deref(const tal_t *ctx, struct wallet *wallet,
|
|||||||
{
|
{
|
||||||
return invoices_iterator_deref(ctx, wallet->invoices, it);
|
return invoices_iterator_deref(ctx, wallet->invoices, it);
|
||||||
}
|
}
|
||||||
void wallet_invoice_resolve(struct wallet *wallet,
|
bool wallet_invoice_resolve(struct wallet *wallet,
|
||||||
struct invoice invoice,
|
struct invoice invoice,
|
||||||
struct amount_msat msatoshi_received)
|
struct amount_msat msatoshi_received)
|
||||||
{
|
{
|
||||||
invoices_resolve(wallet->invoices, invoice, msatoshi_received);
|
return invoices_resolve(wallet->invoices, invoice, msatoshi_received);
|
||||||
}
|
}
|
||||||
void wallet_invoice_waitany(const tal_t *ctx,
|
void wallet_invoice_waitany(const tal_t *ctx,
|
||||||
struct wallet *wallet,
|
struct wallet *wallet,
|
||||||
|
|||||||
@@ -883,10 +883,9 @@ const struct invoice_details *wallet_invoice_iterator_deref(const tal_t *ctx,
|
|||||||
* @invoice - the invoice to mark as paid.
|
* @invoice - the invoice to mark as paid.
|
||||||
* @received - the actual amount received.
|
* @received - the actual amount received.
|
||||||
*
|
*
|
||||||
* Precondition: the invoice must not yet be expired (wallet
|
* If the invoice is not UNPAID, returns false.
|
||||||
* does not check!).
|
|
||||||
*/
|
*/
|
||||||
void wallet_invoice_resolve(struct wallet *wallet,
|
bool wallet_invoice_resolve(struct wallet *wallet,
|
||||||
struct invoice invoice,
|
struct invoice invoice,
|
||||||
struct amount_msat received);
|
struct amount_msat received);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user