mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 14:24:09 +01:00
lightningd: move local invoice resolution into invoice.c function.
We're going to make it async, so start by moving the core code into invoice.c and having that directly call fail/success functions for the htlc. We add an extra check in fulfill_htlc() that the HTLC state is correct: that can't happen now, but may once we're async. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
aa00e26765
commit
6630b99cf7
7 changed files with 118 additions and 56 deletions
|
@ -28,6 +28,7 @@
|
|||
#include <lightningd/log.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
@ -100,6 +101,58 @@ static void wait_on_invoice(const struct invoice *invoice, void *cmd)
|
|||
tell_waiter_deleted((struct command *) cmd);
|
||||
}
|
||||
|
||||
void invoice_try_pay(struct lightningd *ld,
|
||||
struct htlc_in *hin,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct amount_msat msat)
|
||||
{
|
||||
struct invoice invoice;
|
||||
const struct invoice_details *details;
|
||||
|
||||
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:
|
||||
*
|
||||
* An _intermediate hop_ MUST NOT, but the _final node_:
|
||||
*...
|
||||
* - if the amount paid is less than the amount expected:
|
||||
* - MUST fail the HTLC.
|
||||
*/
|
||||
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_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.
|
||||
*/
|
||||
fail_htlc(hin,
|
||||
WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log_info(ld->log, "Resolved invoice '%s' with amount %s",
|
||||
details->label->s,
|
||||
type_to_string(tmpctx, struct amount_msat, &msat));
|
||||
wallet_invoice_resolve(ld->wallet, invoice, msat);
|
||||
fulfill_htlc(hin, &details->r);
|
||||
}
|
||||
|
||||
static bool hsm_sign_b11(const u5 *u5bytes,
|
||||
const u8 *hrpu8,
|
||||
secp256k1_ecdsa_recoverable_signature *rsig,
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
#ifndef LIGHTNING_LIGHTNINGD_INVOICE_H
|
||||
#define LIGHTNING_LIGHTNINGD_INVOICE_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/list/list.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <wire/gen_onion_wire.h>
|
||||
|
||||
struct amount_msat;
|
||||
struct htlc_in;
|
||||
struct lightningd;
|
||||
struct sha256;
|
||||
|
||||
/**
|
||||
* invoice_try_pay - process payment for this payment_hash, amount msat.
|
||||
* @ld: lightningd
|
||||
* @hin: the input HTLC which is offering to pay.
|
||||
* @payment_hash: hash of preimage they want.
|
||||
* @msat: amount they offer to pay.
|
||||
*
|
||||
* Either calls fulfill_htlc() or fail_htlcs().
|
||||
*/
|
||||
void invoice_try_pay(struct lightningd *ld,
|
||||
struct htlc_in *hin,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct amount_msat msat);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_INVOICE_H */
|
||||
|
|
|
@ -135,6 +135,14 @@ static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode,
|
|||
fail_in_htlc(hin, failcode, NULL, out_channel);
|
||||
}
|
||||
|
||||
void fail_htlc(struct htlc_in *hin, enum onion_type failcode)
|
||||
{
|
||||
assert(failcode);
|
||||
/* Final hop never sends an UPDATE. */
|
||||
assert(!(failcode & UPDATE));
|
||||
local_fail_htlc(hin, failcode, NULL);
|
||||
}
|
||||
|
||||
/* localfail are for handing to the local payer if it's local. */
|
||||
static void fail_out_htlc(struct htlc_out *hout, const char *localfail)
|
||||
{
|
||||
|
@ -216,12 +224,19 @@ static bool check_cltv(struct htlc_in *hin,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
|
||||
void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
|
||||
{
|
||||
u8 *msg;
|
||||
struct channel *channel = hin->key.channel;
|
||||
struct wallet *wallet = channel->peer->ld->wallet;
|
||||
|
||||
if (hin->hstate != RCVD_ADD_ACK_REVOCATION) {
|
||||
log_debug(channel->log,
|
||||
"HTLC fulfilled, but not ready any more (%s).",
|
||||
htlc_state_name(hin->hstate));
|
||||
return;
|
||||
}
|
||||
|
||||
hin->preimage = tal_dup(hin, struct preimage, preimage);
|
||||
|
||||
/* We update state now to signal it's in progress, for persistence. */
|
||||
|
@ -259,8 +274,6 @@ static void handle_localpay(struct htlc_in *hin,
|
|||
u32 outgoing_cltv_value)
|
||||
{
|
||||
enum onion_type failcode;
|
||||
struct invoice invoice;
|
||||
const struct invoice_details *details;
|
||||
struct lightningd *ld = hin->key.channel->peer->ld;
|
||||
|
||||
/* BOLT #4:
|
||||
|
@ -289,41 +302,6 @@ static void handle_localpay(struct htlc_in *hin,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) {
|
||||
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
|
||||
goto fail;
|
||||
}
|
||||
details = wallet_invoice_details(tmpctx, ld->wallet, invoice);
|
||||
|
||||
/* BOLT #4:
|
||||
*
|
||||
* An _intermediate hop_ MUST NOT, but the _final node_:
|
||||
*...
|
||||
* - if the amount paid is less than the amount expected:
|
||||
* - MUST fail the HTLC.
|
||||
*/
|
||||
if (details->msat != NULL) {
|
||||
struct amount_msat twice;
|
||||
|
||||
if (amount_msat_less(hin->msat, *details->msat)) {
|
||||
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (amount_msat_add(&twice, *details->msat, *details->msat)
|
||||
&& amount_msat_greater(hin->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.
|
||||
*/
|
||||
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* BOLT #4:
|
||||
*
|
||||
* - if the `cltv_expiry` value is unreasonably near the present:
|
||||
|
@ -341,21 +319,11 @@ static void handle_localpay(struct htlc_in *hin,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
log_info(ld->log, "Resolving invoice '%s' with HTLC %"PRIu64,
|
||||
details->label->s, hin->key.id);
|
||||
log_debug(ld->log, "%s: Actual amount %s, HTLC expiry %u",
|
||||
details->label->s,
|
||||
type_to_string(tmpctx, struct amount_msat, &hin->msat),
|
||||
cltv_expiry);
|
||||
fulfill_htlc(hin, &details->r);
|
||||
wallet_invoice_resolve(ld->wallet, invoice, hin->msat);
|
||||
|
||||
invoice_try_pay(ld, hin, payment_hash, amt_to_forward);
|
||||
return;
|
||||
|
||||
fail:
|
||||
/* Final hop never sends an UPDATE. */
|
||||
assert(!(failcode & UPDATE));
|
||||
local_fail_htlc(hin, failcode, NULL);
|
||||
fail_htlc(hin, failcode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -63,4 +63,8 @@ void htlcs_reconnect(struct lightningd *ld,
|
|||
struct htlc_in_map *htlcs_in,
|
||||
struct htlc_out_map *htlcs_out);
|
||||
|
||||
/* For HTLCs which terminate here, invoice payment calls one of these. */
|
||||
void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage);
|
||||
void fail_htlc(struct htlc_in *hin, enum onion_type failcode);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_PEER_HTLCS_H */
|
||||
|
|
|
@ -73,6 +73,9 @@ void connect_succeeded(struct lightningd *ld UNNEEDED, const struct node_id *id
|
|||
void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED,
|
||||
const struct wireaddr_internal *addrhint TAKES UNNEEDED)
|
||||
{ fprintf(stderr, "delay_then_reconnect called!\n"); abort(); }
|
||||
/* Generated stub for fail_htlc */
|
||||
void fail_htlc(struct htlc_in *hin UNNEEDED, enum onion_type failcode UNNEEDED)
|
||||
{ fprintf(stderr, "fail_htlc called!\n"); abort(); }
|
||||
/* Generated stub for fatal */
|
||||
void fatal(const char *fmt UNNEEDED, ...)
|
||||
{ fprintf(stderr, "fatal called!\n"); abort(); }
|
||||
|
@ -97,6 +100,9 @@ bool fromwire_hsm_sign_invoice_reply(const void *p UNNEEDED, secp256k1_ecdsa_rec
|
|||
/* Generated stub for fromwire_onchain_dev_memleak_reply */
|
||||
bool fromwire_onchain_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_onchain_dev_memleak_reply called!\n"); abort(); }
|
||||
/* Generated stub for fulfill_htlc */
|
||||
void fulfill_htlc(struct htlc_in *hin UNNEEDED, const struct preimage *preimage UNNEEDED)
|
||||
{ fprintf(stderr, "fulfill_htlc called!\n"); abort(); }
|
||||
/* Generated stub for get_block_height */
|
||||
u32 get_block_height(const struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "get_block_height called!\n"); abort(); }
|
||||
|
@ -514,6 +520,11 @@ bool wallet_invoice_find_by_rhash(struct wallet *wallet UNNEEDED,
|
|||
struct invoice *pinvoice UNNEEDED,
|
||||
const struct sha256 *rhash UNNEEDED)
|
||||
{ fprintf(stderr, "wallet_invoice_find_by_rhash called!\n"); abort(); }
|
||||
/* Generated stub for wallet_invoice_find_unpaid */
|
||||
bool wallet_invoice_find_unpaid(struct wallet *wallet UNNEEDED,
|
||||
struct invoice *pinvoice UNNEEDED,
|
||||
const struct sha256 *rhash UNNEEDED)
|
||||
{ fprintf(stderr, "wallet_invoice_find_unpaid called!\n"); abort(); }
|
||||
/* Generated stub for wallet_invoice_iterate */
|
||||
bool wallet_invoice_iterate(struct wallet *wallet UNNEEDED,
|
||||
struct invoice_iterator *it UNNEEDED)
|
||||
|
@ -523,6 +534,11 @@ const struct invoice_details *wallet_invoice_iterator_deref(const tal_t *ctx UNN
|
|||
struct wallet *wallet UNNEEDED,
|
||||
const struct invoice_iterator *it UNNEEDED)
|
||||
{ fprintf(stderr, "wallet_invoice_iterator_deref called!\n"); abort(); }
|
||||
/* Generated stub for wallet_invoice_resolve */
|
||||
void wallet_invoice_resolve(struct wallet *wallet UNNEEDED,
|
||||
struct invoice invoice UNNEEDED,
|
||||
struct amount_msat received UNNEEDED)
|
||||
{ fprintf(stderr, "wallet_invoice_resolve called!\n"); abort(); }
|
||||
/* Generated stub for wallet_invoice_waitany */
|
||||
void wallet_invoice_waitany(const tal_t *ctx UNNEEDED,
|
||||
struct wallet *wallet UNNEEDED,
|
||||
|
|
|
@ -979,8 +979,7 @@ def test_forward_different_fees_and_cltv(node_factory, bitcoind):
|
|||
.format(bitcoind.rpc.getblockcount() + 20 + 9 + shadow_route))
|
||||
l2.daemon.wait_for_log("Adding HTLC 0 amount=4999999msat cltv={} gave CHANNEL_ERR_ADD_OK"
|
||||
.format(bitcoind.rpc.getblockcount() + 9 + shadow_route))
|
||||
l3.daemon.wait_for_log("test_forward_different_fees_and_cltv: Actual amount 4999999msat, HTLC expiry {}"
|
||||
.format(bitcoind.rpc.getblockcount() + 9 + shadow_route))
|
||||
l3.daemon.wait_for_log("Resolved invoice 'test_forward_different_fees_and_cltv' with amount 4999999msat")
|
||||
assert only_one(l3.rpc.listinvoices('test_forward_different_fees_and_cltv')['invoices'])['status'] == 'paid'
|
||||
|
||||
# Check that we see all the channels
|
||||
|
|
|
@ -190,6 +190,12 @@ void invoices_waitone(const tal_t *ctx UNNEEDED,
|
|||
void (*cb)(const struct invoice * UNNEEDED, void*) UNNEEDED,
|
||||
void *cbarg UNNEEDED)
|
||||
{ fprintf(stderr, "invoices_waitone called!\n"); abort(); }
|
||||
/* Generated stub for invoice_try_pay */
|
||||
void invoice_try_pay(struct lightningd *ld UNNEEDED,
|
||||
struct htlc_in *hin UNNEEDED,
|
||||
const struct sha256 *payment_hash UNNEEDED,
|
||||
const struct amount_msat msat UNNEEDED)
|
||||
{ fprintf(stderr, "invoice_try_pay called!\n"); abort(); }
|
||||
/* Generated stub for json_add_address */
|
||||
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
||||
const struct wireaddr *addr UNNEEDED)
|
||||
|
|
Loading…
Add table
Reference in a new issue