From 7f629e545e5a962d3c35ff20886389d6b9761818 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Dec 2019 10:25:45 +1030 Subject: [PATCH] lightningd: split invoice check into separate function. We now return the same error for various "does not match this invoice", so it makes sense to encapsulate these checks. We'll also want to expose this for multi-part payments. Signed-off-by: Rusty Russell --- lightningd/invoice.c | 95 ++++++++++++++++++++++++-------------------- lightningd/invoice.h | 18 +++++++++ 2 files changed, 69 insertions(+), 44 deletions(-) diff --git a/lightningd/invoice.c b/lightningd/invoice.c index ac6fc4e5e..5c13212e2 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -233,51 +233,46 @@ REGISTER_PLUGIN_HOOK(invoice_payment, invoice_payment_serialize, struct invoice_payment_hook_payload *); -void invoice_try_pay(struct lightningd *ld, - struct htlc_in *hin, - const struct sha256 *payment_hash, - const struct amount_msat msat, - const struct secret *payment_secret) +const struct invoice_details * +invoice_check_payment(const tal_t *ctx, + struct lightningd *ld, + const struct sha256 *payment_hash, + const struct amount_msat msat, + const struct secret *payment_secret) { struct invoice invoice; const struct invoice_details *details; - struct invoice_payment_hook_payload *payload; - if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) { - fail_htlc(hin, WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); - return; - } - details = wallet_invoice_details(tmpctx, ld->wallet, invoice); + /* BOLT #4: + * - if the payment hash has already been paid: + * - MAY treat the payment hash as unknown. + * - MAY succeed in accepting the HTLC. + *... + * - if the payment hash is unknown: + * - MUST fail the HTLC. + * - MUST return an `incorrect_or_unknown_payment_details` error. + */ + if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) + return NULL; - log_debug(ld->log, "payment_secret is %s", - payment_secret ? "set": "NULL"); + details = wallet_invoice_details(ctx, ld->wallet, invoice); /* BOLT-9441a66faad63edc8cd89860b22fbf24a86f0dcd #4: - * - * - if the `payment_secret` doesn't match the expected value for that - * `payment_hash`, or the `payment_secret` is required and is not - * present: - * - MUST fail the HTLC. - * - MUST return an `incorrect_or_unknown_payment_details` error. + * - if the `payment_secret` doesn't match the expected value for that + * `payment_hash`, or the `payment_secret` is required and is not + * present: + * - MUST fail the HTLC. */ if (feature_is_set(details->features, COMPULSORY_FEATURE(OPT_VAR_ONION)) - && !payment_secret) { - fail_htlc(hin, WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); - return; - } + && !payment_secret) + return tal_free(details); if (payment_secret) { struct secret expected; invoice_secret(&details->r, &expected); - log_debug(ld->log, "payment_secret %s vs %s", - type_to_string(tmpctx, struct secret, payment_secret), - type_to_string(tmpctx, struct secret, &expected)); - if (!secret_eq_consttime(payment_secret, &expected)) { - fail_htlc(hin, - WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); - return; - } + if (!secret_eq_consttime(payment_secret, &expected)) + return tal_free(details); } /* BOLT #4: @@ -290,26 +285,39 @@ void invoice_try_pay(struct lightningd *ld, if (details->msat != NULL) { struct amount_msat twice; - if (amount_msat_less(msat, *details->msat)) { - fail_htlc(hin, - WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); - return; - } + if (amount_msat_less(msat, *details->msat)) + return tal_free(details); if (amount_msat_add(&twice, *details->msat, *details->msat) && amount_msat_greater(msat, twice)) { - /* FIXME: bolt update fixes this quote! */ /* BOLT #4: * - * - if the amount paid is more than twice the amount expected: - * - SHOULD fail the HTLC. - * - SHOULD return an `incorrect_or_unknown_payment_details` error. + * - if the amount paid is more than twice the amount + * expected: + * - SHOULD fail the HTLC. */ - fail_htlc(hin, - WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); - return; + return tal_free(details); } } + return details; +} + +void invoice_try_pay(struct lightningd *ld, + struct htlc_in *hin, + const struct sha256 *payment_hash, + const struct amount_msat msat, + const struct secret *payment_secret) +{ + const struct invoice_details *details; + struct invoice_payment_hook_payload *payload; + + details = invoice_check_payment(tmpctx, ld, payment_hash, msat, + payment_secret); + + if (!details) { + fail_htlc(hin, WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS); + return; + } payload = tal(ld, struct invoice_payment_hook_payload); payload->ld = ld; @@ -319,7 +327,6 @@ void invoice_try_pay(struct lightningd *ld, payload->hin = hin; tal_add_destructor2(hin, invoice_payload_remove_hin, payload); - log_debug(ld->log, "Calling hook for invoice '%s'", details->label->s); plugin_hook_call_invoice_payment(ld, payload, payload); } diff --git a/lightningd/invoice.h b/lightningd/invoice.h index 954c8c36e..199ab4b90 100644 --- a/lightningd/invoice.h +++ b/lightningd/invoice.h @@ -8,6 +8,24 @@ struct htlc_in; struct lightningd; struct sha256; + +/** + * invoice_check_payment - check if this payment would be valid + * @ctx: tal context to allocate return off + * @ld: lightningd + * @payment_hash: hash of preimage they want. + * @msat: amount they offer to pay. + * @payment_secret: they payment secret they sent, if any. + * + * Returns NULL if there's a problem, otherwise returns the invoice details. + */ +const struct invoice_details * +invoice_check_payment(const tal_t *ctx, + struct lightningd *ld, + const struct sha256 *payment_hash, + const struct amount_msat msat, + const struct secret *payment_secret); + /** * invoice_try_pay - process payment for this payment_hash, amount msat. * @ld: lightningd