Browse Source

lightningd: sew in htlc set.

The invoice_try_pay code now takes a set, rather than a single htlc, but
it's basically the same thing.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-debug
Rusty Russell 5 years ago
committed by Christian Decker
parent
commit
8e3234e67a
  1. 3
      lightningd/htlc_set.c
  2. 49
      lightningd/invoice.c
  3. 18
      lightningd/invoice.h
  4. 15
      lightningd/peer_htlcs.c
  5. 12
      lightningd/test/run-invoice-select-inchan.c
  6. 13
      tests/test_pay.py
  7. 13
      wallet/test/run-wallet.c

3
lightningd/htlc_set.c

@ -178,8 +178,7 @@ void htlc_set_add(struct lightningd *ld,
}
if (amount_msat_eq(set->so_far, total_msat)) {
/* FIXME: hand to invoice_try_pay! */
tal_free(set);
invoice_try_pay(ld, set, details);
return;
}

49
lightningd/invoice.c

@ -123,7 +123,7 @@ static void invoice_secret(const struct preimage *payment_preimage,
struct invoice_payment_hook_payload {
struct lightningd *ld;
/* Set to NULL if it is deleted while waiting for plugin */
struct htlc_in *hin;
struct htlc_set *set;
/* What invoice it's trying to pay. */
const struct json_escape *label;
/* Amount it's offering. */
@ -146,12 +146,13 @@ invoice_payment_serialize(struct invoice_payment_hook_payload *payload,
json_object_end(stream); /* .payment */
}
/* Peer dies? Remove hin ptr from payload so we know to ignore plugin return */
static void invoice_payload_remove_hin(struct htlc_in *hin,
/* Set times out or HTLC deleted? Remove set ptr from payload so we
* know to ignore plugin return */
static void invoice_payload_remove_set(struct htlc_set *set,
struct invoice_payment_hook_payload *payload)
{
assert(payload->hin == hin);
payload->hin = NULL;
assert(payload->set == set);
payload->set = NULL;
}
static bool hook_gives_failcode(const char *buffer,
@ -195,12 +196,12 @@ invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload,
* called even if the hook is not registered. */
notify_invoice_payment(ld, payload->msat, payload->preimage, payload->label);
tal_del_destructor2(payload->hin, invoice_payload_remove_hin, payload);
tal_del_destructor2(payload->set, invoice_payload_remove_set, payload);
/* We want to free this, whatever happens. */
tal_steal(tmpctx, payload);
/* If peer dies or something, this can happen. */
if (!payload->hin) {
if (!payload->set) {
log_debug(ld->log, "invoice '%s' paying htlc_in has gone!",
payload->label->s);
return;
@ -210,21 +211,22 @@ invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload,
* we can also fail */
if (!wallet_invoice_find_by_label(ld->wallet, &invoice, payload->label)) {
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
fail_htlc(payload->hin, failcode);
htlc_set_fail(payload->set, failcode);
return;
}
/* Did we have a hook result? */
if (hook_gives_failcode(buffer, toks, &failcode)) {
fail_htlc(payload->hin, failcode);
htlc_set_fail(payload->set, failcode);
return;
}
log_info(ld->log, "Resolved invoice '%s' with amount %s",
payload->label->s,
type_to_string(tmpctx, struct amount_msat, &payload->msat));
log_info(ld->log, "Resolved invoice '%s' with amount %s in %zu htlcs",
payload->label->s,
type_to_string(tmpctx, struct amount_msat, &payload->msat),
tal_count(payload->set->htlcs));
wallet_invoice_resolve(ld->wallet, invoice, payload->msat);
fulfill_htlc(payload->hin, &payload->preimage);
htlc_set_fulfill(payload->set, &payload->preimage);
}
REGISTER_PLUGIN_HOOK(invoice_payment,
@ -303,29 +305,18 @@ invoice_check_payment(const tal_t *ctx,
}
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)
struct htlc_set *set,
const struct invoice_details *details)
{
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;
payload->label = tal_steal(payload, details->label);
payload->msat = msat;
payload->msat = set->so_far;
payload->preimage = details->r;
payload->hin = hin;
tal_add_destructor2(hin, invoice_payload_remove_hin, payload);
payload->set = set;
tal_add_destructor2(set, invoice_payload_remove_set, payload);
plugin_hook_call_invoice_payment(ld, payload, payload);
}

18
lightningd/invoice.h

@ -4,7 +4,7 @@
#include <wire/gen_onion_wire.h>
struct amount_msat;
struct htlc_in;
struct htlc_set;
struct lightningd;
struct sha256;
@ -27,19 +27,15 @@ invoice_check_payment(const tal_t *ctx,
const struct secret *payment_secret);
/**
* invoice_try_pay - process payment for this payment_hash, amount msat.
* invoice_try_pay - process payment for these incoming payments.
* @ld: lightningd
* @hin: the input HTLC which is offering to pay.
* @payment_hash: hash of preimage they want.
* @msat: amount they offer to pay.
* @payment_secret: they payment secret they sent, if any.
* @set: the htlc_set used to pay this.
* @details: returned from successful invoice_check_payment.
*
* Either calls fulfill_htlc() or fail_htlcs().
* Either calls fulfill_htlc_set() or fail_htlc_set().
*/
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);
struct htlc_set *set,
const struct invoice_details *details);
#endif /* LIGHTNING_LIGHTNINGD_INVOICE_H */

15
lightningd/peer_htlcs.c

@ -17,6 +17,7 @@
#include <gossipd/gen_gossip_wire.h>
#include <lightningd/chaintopology.h>
#include <lightningd/htlc_end.h>
#include <lightningd/htlc_set.h>
#include <lightningd/json.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
@ -299,18 +300,6 @@ static void handle_localpay(struct htlc_in *hin,
goto fail;
}
/* BOLT-9441a66faad63edc8cd89860b22fbf24a86f0dcd #4:
* - if it does not support `basic_mpp`:
* - MUST fail the HTLC if `total_msat` is not exactly equal to
* `amt_to_forward`.
*/
if (!amount_msat_eq(amt_to_forward, total_msat)) {
/* FIXME: Ideally, we use WIRE_INVALID_ONION_PAYLOAD and
* point at the total_msat field */
failcode = WIRE_FINAL_INCORRECT_HTLC_AMOUNT;
goto fail;
}
/* BOLT #4:
*
* 1. type: 18 (`final_incorrect_cltv_expiry`)
@ -341,7 +330,7 @@ static void handle_localpay(struct htlc_in *hin,
goto fail;
}
invoice_try_pay(ld, hin, &hin->payment_hash, amt_to_forward, payment_secret);
htlc_set_add(ld, hin, total_msat, payment_secret);
return;
fail:

12
lightningd/test/run-invoice-select-inchan.c

@ -87,9 +87,6 @@ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
const struct chainparams *chainparams UNNEEDED,
const u8 *scriptPubkey UNNEEDED)
{ fprintf(stderr, "encode_scriptpubkey_to_addr 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(); }
@ -120,9 +117,6 @@ 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(); }
@ -136,6 +130,12 @@ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
struct amount_sat dust_limit UNNEEDED,
enum side side UNNEEDED)
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
/* Generated stub for htlc_set_fail */
void htlc_set_fail(struct htlc_set *set UNNEEDED, enum onion_type failcode UNNEEDED)
{ fprintf(stderr, "htlc_set_fail called!\n"); abort(); }
/* Generated stub for htlc_set_fulfill */
void htlc_set_fulfill(struct htlc_set *set UNNEEDED, const struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "htlc_set_fulfill 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)

13
tests/test_pay.py

@ -2625,16 +2625,15 @@ def test_partial_payment(node_factory, bitcoind, executor):
l2.daemon.wait_for_log(r'dev_disconnect')
l3.daemon.wait_for_log(r'dev_disconnect')
# Now continue, payments will fail because receiver doesn't do MPP.
# Now continue, payments will succeed due to MPP.
l2.rpc.dev_reenable_commit(l4.info['id'])
l3.rpc.dev_reenable_commit(l4.info['id'])
# See FIXME in peer_htlcs: WIRE_INVALID_ONION_PAYLOAD would be better.
with pytest.raises(RpcError, match=r'WIRE_FINAL_INCORRECT_HTLC_AMOUNT'):
l1.rpc.call('waitsendpay', [inv['payment_hash'], None, 1])
with pytest.raises(RpcError, match=r'WIRE_FINAL_INCORRECT_HTLC_AMOUNT'):
l1.rpc.call('waitsendpay', {'payment_hash': inv['payment_hash'],
'partid': 2})
res = l1.rpc.call('waitsendpay', [inv['payment_hash'], None, 1])
assert res['partid'] == 1
res = l1.rpc.call('waitsendpay', {'payment_hash': inv['payment_hash'],
'partid': 2})
assert res['partid'] == 2
for i in range(2):
line = l4.daemon.wait_for_log('print_htlc_onion.py: Got onion')

13
wallet/test/run-wallet.c

@ -130,6 +130,12 @@ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
struct amount_sat dust_limit UNNEEDED,
enum side side UNNEEDED)
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
/* Generated stub for htlc_set_add */
void htlc_set_add(struct lightningd *ld UNNEEDED,
struct htlc_in *hin UNNEEDED,
struct amount_msat total_msat UNNEEDED,
const struct secret *payment_secret UNNEEDED)
{ fprintf(stderr, "htlc_set_add called!\n"); abort(); }
/* Generated stub for invoices_create */
bool invoices_create(struct invoices *invoices UNNEEDED,
struct invoice *pinvoice UNNEEDED,
@ -203,13 +209,6 @@ 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,
const struct secret *payment_secret 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…
Cancel
Save