Skip to content

Commit

Permalink
lightningd: move local invoice resolution into invoice.c function.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
rustyrussell committed Apr 12, 2019
1 parent aa00e26 commit 6630b99
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 56 deletions.
53 changes: 53 additions & 0 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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,
Expand Down
24 changes: 20 additions & 4 deletions lightningd/invoice.h
Original file line number Diff line number Diff line change
@@ -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 */
68 changes: 18 additions & 50 deletions lightningd/peer_htlcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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);
}

/*
Expand Down
4 changes: 4 additions & 0 deletions lightningd/peer_htlcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
16 changes: 16 additions & 0 deletions lightningd/test/run-invoice-select-inchan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }
Expand All @@ -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(); }
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions wallet/test/run-wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 6630b99

Please sign in to comment.