lightningd: add invoice_amt to the htlc_accepted hook

This commit introduces a new field `invoice_msat` to the htlc_accepted
hook. If this field is specified it will replace the amount of the
invoice that belongs to the payment_hash of the HTLC on internal checks.

This is useful in scenarios where we actually expect a smaller amount
than initially specified in an invoice.

Changelog-Changed: Plugins: `htlc_accepted` hook can now override the
expected total amount of the invoice that belongs to the HTLC.

Signed-off-by: Peter Neuroth <pet.v.ne@gmail.com>
This commit is contained in:
Peter Neuroth
2025-11-06 16:40:08 +01:00
committed by Rusty Russell
parent 572c4553a2
commit 21fb7600f3
8 changed files with 96 additions and 6 deletions

View File

@@ -133,6 +133,7 @@ void htlc_set_add_(struct lightningd *ld,
struct logger *log,
struct amount_msat msat,
struct amount_msat total_msat,
const struct amount_msat *invoice_msat_override,
const struct sha256 *payment_hash,
const struct secret *payment_secret,
void (*fail)(void *, const u8 *),
@@ -151,7 +152,8 @@ void htlc_set_add_(struct lightningd *ld,
* - Note: "amount paid" specified there is the `total_msat` field.
*/
details = invoice_check_payment(tmpctx, ld, payment_hash, total_msat,
NULL, payment_secret, &err);
invoice_msat_override, payment_secret,
&err);
if (!details) {
log_debug(log, "payment failed: %s", err);
fail(arg, take(failmsg_incorrect_or_unknown(NULL, ld, msat)));

View File

@@ -60,15 +60,17 @@ void htlc_set_add_(struct lightningd *ld,
struct logger *log,
struct amount_msat msat,
struct amount_msat total_msat,
const struct amount_msat *invoice_msat_override,
const struct sha256 *payment_hash,
const struct secret *payment_secret,
void (*fail)(void *, const u8 *),
void (*succeeded)(void *, const struct preimage *),
void *arg);
#define htlc_set_add(ld, log, msat, total_msat, payment_hash, payment_secret, \
fail, succeeded, arg) \
htlc_set_add_((ld), (log), (msat), (total_msat), (payment_hash), \
#define htlc_set_add(ld, log, msat, total_msat, invoice_msat_override, \
payment_hash, payment_secret, fail, succeeded, arg)\
htlc_set_add_((ld), (log), (msat), (total_msat), \
(invoice_msat_override), (payment_hash), \
(payment_secret), \
typesafe_cb_postargs(void, void *, \
(fail), (arg), \

View File

@@ -1973,7 +1973,7 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
* not resolve immediately */
fixme_ignore(command_still_pending(cmd));
htlc_set_add(cmd->ld, cmd->ld->log, *msat, *payload->total_msat,
payment_hash, payload->payment_secret,
NULL, payment_hash, payload->payment_secret,
selfpay_mpp_fail, selfpay_mpp_succeeded,
selfpay);
return command_its_complicated("htlc_set_add may have immediately succeeded or failed");

View File

@@ -3,9 +3,11 @@
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <channeld/channeld_wiregen.h>
#include <common/amount.h>
#include <common/blinding.h>
#include <common/ecdh.h>
#include <common/json_command.h>
#include <common/json_parse.h>
#include <common/onion_decode.h>
#include <common/onionreply.h>
#include <common/timeout.h>
@@ -435,6 +437,7 @@ static void handle_localpay(struct htlc_in *hin,
struct amount_msat amt_to_forward,
u32 outgoing_cltv_value,
struct amount_msat total_msat,
const struct amount_msat *invoice_msat_override,
const struct secret *payment_secret,
const u8 *payment_metadata)
{
@@ -525,6 +528,7 @@ static void handle_localpay(struct htlc_in *hin,
htlc_set_add(ld, hin->key.channel->log,
hin->msat, total_msat,
invoice_msat_override,
&hin->payment_hash,
payment_secret,
local_fail_in_htlc,
@@ -947,6 +951,9 @@ struct htlc_accepted_hook_payload {
size_t failtlvpos;
const char *failexplanation;
u8 *extra_tlvs_raw;
/* Default is NULL, if NOT NULL: used to override the amount of the
* invoice this htlc belongs to in checks! */
struct amount_msat *invoice_msat;
};
static void
@@ -1003,7 +1010,8 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
struct htlc_in *hin = request->hin;
struct lightningd *ld = request->ld;
struct preimage payment_preimage;
const jsmntok_t *resulttok, *paykeytok, *payloadtok, *fwdtok, *extra_tlvs_tok;
const jsmntok_t *resulttok, *paykeytok, *payloadtok, *fwdtok, *extra_tlvs_tok,
*invmsattok;
u8 *failonion, *raw_tlvs;
if (!toks || !buffer)
@@ -1018,6 +1026,17 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
json_strdup(tmpctx, buffer, toks));
}
invmsattok = json_get_member(buffer, toks, "invoice_msat");
if (invmsattok) {
tal_free(request->invoice_msat);
request->invoice_msat = tal(request, struct amount_msat);
if (!json_to_msat(buffer, invmsattok, request->invoice_msat)) {
fatal("Bad invoice_msat for htlc_accepted hook: %.*s",
invmsattok->end - invmsattok->start,
buffer + invmsattok->start);
}
}
extra_tlvs_tok = json_get_member(buffer, toks, "extra_tlvs");
if (extra_tlvs_tok) {
size_t max;
@@ -1275,6 +1294,7 @@ htlc_accepted_hook_final(struct htlc_accepted_hook_payload *request STEALS)
request->payload->amt_to_forward,
request->payload->outgoing_cltv,
*request->payload->total_msat,
request->invoice_msat,
request->payload->payment_secret,
request->payload->payment_metadata);
@@ -1555,6 +1575,11 @@ static bool peer_accepted_htlc(const tal_t *ctx,
hook_payload->extra_tlvs_raw = NULL;
}
/* We don't set the invoice amount here, if it is set during a hook
* response, it will be used to override the actual invoice amount on
* later checks. */
hook_payload->invoice_msat = NULL;
plugin_hook_call_htlc_accepted(ld, NULL, hook_payload);
/* Falling through here is ok, after all the HTLC locked */