mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
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>
This commit is contained in:
parent
c2b357b916
commit
8e3234e67a
@ -178,8 +178,7 @@ void htlc_set_add(struct lightningd *ld,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (amount_msat_eq(set->so_far, total_msat)) {
|
if (amount_msat_eq(set->so_far, total_msat)) {
|
||||||
/* FIXME: hand to invoice_try_pay! */
|
invoice_try_pay(ld, set, details);
|
||||||
tal_free(set);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ static void invoice_secret(const struct preimage *payment_preimage,
|
|||||||
struct invoice_payment_hook_payload {
|
struct invoice_payment_hook_payload {
|
||||||
struct lightningd *ld;
|
struct lightningd *ld;
|
||||||
/* Set to NULL if it is deleted while waiting for plugin */
|
/* 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. */
|
/* What invoice it's trying to pay. */
|
||||||
const struct json_escape *label;
|
const struct json_escape *label;
|
||||||
/* Amount it's offering. */
|
/* Amount it's offering. */
|
||||||
@ -146,12 +146,13 @@ invoice_payment_serialize(struct invoice_payment_hook_payload *payload,
|
|||||||
json_object_end(stream); /* .payment */
|
json_object_end(stream); /* .payment */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Peer dies? Remove hin ptr from payload so we know to ignore plugin return */
|
/* Set times out or HTLC deleted? Remove set ptr from payload so we
|
||||||
static void invoice_payload_remove_hin(struct htlc_in *hin,
|
* know to ignore plugin return */
|
||||||
|
static void invoice_payload_remove_set(struct htlc_set *set,
|
||||||
struct invoice_payment_hook_payload *payload)
|
struct invoice_payment_hook_payload *payload)
|
||||||
{
|
{
|
||||||
assert(payload->hin == hin);
|
assert(payload->set == set);
|
||||||
payload->hin = NULL;
|
payload->set = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hook_gives_failcode(const char *buffer,
|
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. */
|
* called even if the hook is not registered. */
|
||||||
notify_invoice_payment(ld, payload->msat, payload->preimage, payload->label);
|
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. */
|
/* We want to free this, whatever happens. */
|
||||||
tal_steal(tmpctx, payload);
|
tal_steal(tmpctx, payload);
|
||||||
|
|
||||||
/* If peer dies or something, this can happen. */
|
/* 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!",
|
log_debug(ld->log, "invoice '%s' paying htlc_in has gone!",
|
||||||
payload->label->s);
|
payload->label->s);
|
||||||
return;
|
return;
|
||||||
@ -210,21 +211,22 @@ invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload,
|
|||||||
* we can also fail */
|
* we can also fail */
|
||||||
if (!wallet_invoice_find_by_label(ld->wallet, &invoice, payload->label)) {
|
if (!wallet_invoice_find_by_label(ld->wallet, &invoice, payload->label)) {
|
||||||
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
|
failcode = WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS;
|
||||||
fail_htlc(payload->hin, failcode);
|
htlc_set_fail(payload->set, failcode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Did we have a hook result? */
|
/* Did we have a hook result? */
|
||||||
if (hook_gives_failcode(buffer, toks, &failcode)) {
|
if (hook_gives_failcode(buffer, toks, &failcode)) {
|
||||||
fail_htlc(payload->hin, failcode);
|
htlc_set_fail(payload->set, failcode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info(ld->log, "Resolved invoice '%s' with amount %s",
|
log_info(ld->log, "Resolved invoice '%s' with amount %s in %zu htlcs",
|
||||||
payload->label->s,
|
payload->label->s,
|
||||||
type_to_string(tmpctx, struct amount_msat, &payload->msat));
|
type_to_string(tmpctx, struct amount_msat, &payload->msat),
|
||||||
|
tal_count(payload->set->htlcs));
|
||||||
wallet_invoice_resolve(ld->wallet, invoice, payload->msat);
|
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,
|
REGISTER_PLUGIN_HOOK(invoice_payment,
|
||||||
@ -303,29 +305,18 @@ invoice_check_payment(const tal_t *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void invoice_try_pay(struct lightningd *ld,
|
void invoice_try_pay(struct lightningd *ld,
|
||||||
struct htlc_in *hin,
|
struct htlc_set *set,
|
||||||
const struct sha256 *payment_hash,
|
const struct invoice_details *details)
|
||||||
const struct amount_msat msat,
|
|
||||||
const struct secret *payment_secret)
|
|
||||||
{
|
{
|
||||||
const struct invoice_details *details;
|
|
||||||
struct invoice_payment_hook_payload *payload;
|
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 = tal(ld, struct invoice_payment_hook_payload);
|
||||||
payload->ld = ld;
|
payload->ld = ld;
|
||||||
payload->label = tal_steal(payload, details->label);
|
payload->label = tal_steal(payload, details->label);
|
||||||
payload->msat = msat;
|
payload->msat = set->so_far;
|
||||||
payload->preimage = details->r;
|
payload->preimage = details->r;
|
||||||
payload->hin = hin;
|
payload->set = set;
|
||||||
tal_add_destructor2(hin, invoice_payload_remove_hin, payload);
|
tal_add_destructor2(set, invoice_payload_remove_set, payload);
|
||||||
|
|
||||||
plugin_hook_call_invoice_payment(ld, payload, payload);
|
plugin_hook_call_invoice_payment(ld, payload, payload);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <wire/gen_onion_wire.h>
|
#include <wire/gen_onion_wire.h>
|
||||||
|
|
||||||
struct amount_msat;
|
struct amount_msat;
|
||||||
struct htlc_in;
|
struct htlc_set;
|
||||||
struct lightningd;
|
struct lightningd;
|
||||||
struct sha256;
|
struct sha256;
|
||||||
|
|
||||||
@ -27,19 +27,15 @@ invoice_check_payment(const tal_t *ctx,
|
|||||||
const struct secret *payment_secret);
|
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
|
* @ld: lightningd
|
||||||
* @hin: the input HTLC which is offering to pay.
|
* @set: the htlc_set used to pay this.
|
||||||
* @payment_hash: hash of preimage they want.
|
* @details: returned from successful invoice_check_payment.
|
||||||
* @msat: amount they offer to pay.
|
|
||||||
* @payment_secret: they payment secret they sent, if any.
|
|
||||||
*
|
*
|
||||||
* Either calls fulfill_htlc() or fail_htlcs().
|
* Either calls fulfill_htlc_set() or fail_htlc_set().
|
||||||
*/
|
*/
|
||||||
void invoice_try_pay(struct lightningd *ld,
|
void invoice_try_pay(struct lightningd *ld,
|
||||||
struct htlc_in *hin,
|
struct htlc_set *set,
|
||||||
const struct sha256 *payment_hash,
|
const struct invoice_details *details);
|
||||||
const struct amount_msat msat,
|
|
||||||
const struct secret *payment_secret);
|
|
||||||
|
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_INVOICE_H */
|
#endif /* LIGHTNING_LIGHTNINGD_INVOICE_H */
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <gossipd/gen_gossip_wire.h>
|
#include <gossipd/gen_gossip_wire.h>
|
||||||
#include <lightningd/chaintopology.h>
|
#include <lightningd/chaintopology.h>
|
||||||
#include <lightningd/htlc_end.h>
|
#include <lightningd/htlc_end.h>
|
||||||
|
#include <lightningd/htlc_set.h>
|
||||||
#include <lightningd/json.h>
|
#include <lightningd/json.h>
|
||||||
#include <lightningd/jsonrpc.h>
|
#include <lightningd/jsonrpc.h>
|
||||||
#include <lightningd/lightningd.h>
|
#include <lightningd/lightningd.h>
|
||||||
@ -299,18 +300,6 @@ static void handle_localpay(struct htlc_in *hin,
|
|||||||
goto fail;
|
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:
|
/* BOLT #4:
|
||||||
*
|
*
|
||||||
* 1. type: 18 (`final_incorrect_cltv_expiry`)
|
* 1. type: 18 (`final_incorrect_cltv_expiry`)
|
||||||
@ -341,7 +330,7 @@ static void handle_localpay(struct htlc_in *hin,
|
|||||||
goto fail;
|
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;
|
return;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -87,9 +87,6 @@ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
|
|||||||
const struct chainparams *chainparams UNNEEDED,
|
const struct chainparams *chainparams UNNEEDED,
|
||||||
const u8 *scriptPubkey UNNEEDED)
|
const u8 *scriptPubkey UNNEEDED)
|
||||||
{ fprintf(stderr, "encode_scriptpubkey_to_addr called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for fatal */
|
||||||
void fatal(const char *fmt UNNEEDED, ...)
|
void fatal(const char *fmt UNNEEDED, ...)
|
||||||
{ fprintf(stderr, "fatal called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for fromwire_onchain_dev_memleak_reply */
|
||||||
bool fromwire_onchain_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
bool fromwire_onchain_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
||||||
{ fprintf(stderr, "fromwire_onchain_dev_memleak_reply called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for get_block_height */
|
||||||
u32 get_block_height(const struct chain_topology *topo UNNEEDED)
|
u32 get_block_height(const struct chain_topology *topo UNNEEDED)
|
||||||
{ fprintf(stderr, "get_block_height called!\n"); abort(); }
|
{ 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,
|
struct amount_sat dust_limit UNNEEDED,
|
||||||
enum side side UNNEEDED)
|
enum side side UNNEEDED)
|
||||||
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for json_add_address */
|
||||||
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
||||||
const struct wireaddr *addr UNNEEDED)
|
const struct wireaddr *addr UNNEEDED)
|
||||||
|
@ -2625,16 +2625,15 @@ def test_partial_payment(node_factory, bitcoind, executor):
|
|||||||
l2.daemon.wait_for_log(r'dev_disconnect')
|
l2.daemon.wait_for_log(r'dev_disconnect')
|
||||||
l3.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'])
|
l2.rpc.dev_reenable_commit(l4.info['id'])
|
||||||
l3.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.
|
res = l1.rpc.call('waitsendpay', [inv['payment_hash'], None, 1])
|
||||||
with pytest.raises(RpcError, match=r'WIRE_FINAL_INCORRECT_HTLC_AMOUNT'):
|
assert res['partid'] == 1
|
||||||
l1.rpc.call('waitsendpay', [inv['payment_hash'], None, 1])
|
res = l1.rpc.call('waitsendpay', {'payment_hash': inv['payment_hash'],
|
||||||
with pytest.raises(RpcError, match=r'WIRE_FINAL_INCORRECT_HTLC_AMOUNT'):
|
'partid': 2})
|
||||||
l1.rpc.call('waitsendpay', {'payment_hash': inv['payment_hash'],
|
assert res['partid'] == 2
|
||||||
'partid': 2})
|
|
||||||
|
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
line = l4.daemon.wait_for_log('print_htlc_onion.py: Got onion')
|
line = l4.daemon.wait_for_log('print_htlc_onion.py: Got onion')
|
||||||
|
@ -130,6 +130,12 @@ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
|
|||||||
struct amount_sat dust_limit UNNEEDED,
|
struct amount_sat dust_limit UNNEEDED,
|
||||||
enum side side UNNEEDED)
|
enum side side UNNEEDED)
|
||||||
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for invoices_create */
|
||||||
bool invoices_create(struct invoices *invoices UNNEEDED,
|
bool invoices_create(struct invoices *invoices UNNEEDED,
|
||||||
struct invoice *pinvoice 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 (*cb)(const struct invoice * UNNEEDED, void*) UNNEEDED,
|
||||||
void *cbarg UNNEEDED)
|
void *cbarg UNNEEDED)
|
||||||
{ fprintf(stderr, "invoices_waitone called!\n"); abort(); }
|
{ 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 */
|
/* Generated stub for json_add_address */
|
||||||
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
||||||
const struct wireaddr *addr UNNEEDED)
|
const struct wireaddr *addr UNNEEDED)
|
||||||
|
Loading…
Reference in New Issue
Block a user