Skip to content

Commit

Permalink
invoice: hack in merkle of invoice as "payment_secret" (EXPERIMENTAL_…
Browse files Browse the repository at this point in the history
…FEATURES)

This lets actually pay the invoice that fetchinvoice returns.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Dec 14, 2020
1 parent 513636f commit 018ca05
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
30 changes: 30 additions & 0 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,31 @@ static void invoice_secret(const struct preimage *payment_preimage,
memcpy(payment_secret->data, secret.u.u8, sizeof(secret.u.u8));
}

#if EXPERIMENTAL_FEATURES
/* FIXME: This is a hack. The real secret should be a signature of some
* onion key, using the payer_id */
static void invoice_secret_bolt12(struct lightningd *ld,
const char *invstring,
struct secret *payment_secret)
{
char *fail;
struct tlv_invoice *inv;
struct sha256 merkle;

inv = invoice_decode(tmpctx, invstring, strlen(invstring),
NULL, NULL, &fail);
if (!inv) {
log_broken(ld->log, "Unable to decode our invoice %s",
invstring);
return;
}

merkle_tlv(inv->fields, &merkle);
BUILD_ASSERT(sizeof(*payment_secret) == sizeof(merkle));
memcpy(payment_secret, &merkle, sizeof(merkle));
}
#endif /* EXPERIMENTAL_FEATURES */

struct invoice_payment_hook_payload {
struct lightningd *ld;
/* Set to NULL if it is deleted while waiting for plugin */
Expand Down Expand Up @@ -348,6 +373,11 @@ invoice_check_payment(const tal_t *ctx,
if (payment_secret) {
struct secret expected;

#if EXPERIMENTAL_FEATURES
if (details->invstring && strstarts(details->invstring, "lni1"))
invoice_secret_bolt12(ld, details->invstring, &expected);
else
#endif /* EXPERIMENTAL_FEATURES */
invoice_secret(&details->r, &expected);
if (!secret_eq_consttime(payment_secret, &expected)) {
log_debug(ld->log, "Attept to pay %s with wrong secret",
Expand Down
7 changes: 7 additions & 0 deletions lightningd/test/run-invoice-select-inchan.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,13 @@ struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx UNNEEDED,
/* Generated stub for invoice_encode */
char *invoice_encode(const tal_t *ctx UNNEEDED, const struct tlv_invoice *bolt12_tlv UNNEEDED)
{ fprintf(stderr, "invoice_encode called!\n"); abort(); }
/* Generated stub for invoice_decode */
struct tlv_invoice *invoice_decode(const tal_t *ctx UNNEEDED,
const char *b12 UNNEEDED, size_t b12len UNNEEDED,
const struct feature_set *our_features UNNEEDED,
const struct chainparams *must_be_chain UNNEEDED,
char **fail UNNEEDED)
{ fprintf(stderr, "invoice_decode called!\n"); abort(); }
#endif

static void add_candidate(struct routehint_candidate **candidates, int n,
Expand Down
33 changes: 33 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3856,6 +3856,8 @@ def test_fetchinvoice(node_factory, bitcoind):
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer})
assert inv1 != inv2
l1.rpc.pay(inv1['invoice'])
l1.rpc.pay(inv2['invoice'])

# Single-use invoice can be fetched multiple times, only paid once.
offer = l3.rpc.call('offer', {'amount': '1msat',
Expand All @@ -3866,3 +3868,34 @@ def test_fetchinvoice(node_factory, bitcoind):
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer})
assert inv1 != inv2

l1.rpc.pay(inv1['invoice'])

# FIXME: We don't report failure yet.
# # We can't pay the other one now.
# with pytest.raises(RpcError, match='???'):
# l1.rpc.pay(inv2['invoice'])
#
# # We can't reuse the offer, either.
# with pytest.raises(RpcError, match='???'):
# l1.rpc.call('fetchinvoice', {'offer': offer})

# Recurring offer.
offer = l2.rpc.call('offer', {'amount': '1msat',
'description': 'recurring test',
'recurrence': '1minutes'})['bolt12']
print(offer)

ret = l1.rpc.call('fetchinvoice', {'offer': offer,
'recurrence_counter': 0,
'recurrence_label': 'test recurrence'})
print(ret)

l1.rpc.pay(ret['invoice'], label='test recurrence')

ret = l1.rpc.call('fetchinvoice', {'offer': offer,
'recurrence_counter': 1,
'recurrence_label': 'test recurrence'})
print(ret)

l1.rpc.pay(ret['invoice'], label='test recurrence')

0 comments on commit 018ca05

Please sign in to comment.