Skip to content

Commit

Permalink
lightningd: populate listsendpays destination from injectpaymentonion…
Browse files Browse the repository at this point in the history
… if we can.

If they give us the invstring, we can at least set who signed the invoice.  Of course,
it might not be a real node_id (with blinded paths).

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Dec 17, 2024
1 parent cf0bd39 commit dc6a5f8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 8 deletions.
34 changes: 30 additions & 4 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1788,7 +1788,8 @@ static void register_payment_and_waiter(struct command *cmd,
const char *label,
const char *invstring,
struct sha256 *local_invreq_id,
const struct secret *shared_secret)
const struct secret *shared_secret,
const struct node_id *destination TAKES)
{
wallet_add_payment(cmd,
cmd->ld->wallet,
Expand All @@ -1798,7 +1799,7 @@ static void register_payment_and_waiter(struct command *cmd,
partid,
groupid,
PAYMENT_PENDING,
NULL,
destination,
destination_msat,
msat_sent,
total_msat,
Expand Down Expand Up @@ -1845,6 +1846,7 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
struct htlc_out *hout;
const struct wallet_payment *prev_payment;
const char *explanation;
struct node_id *destination;

if (!param_check(cmd, buffer, params,
p_req("onion", param_bin_from_hex, &onion),
Expand Down Expand Up @@ -1926,6 +1928,28 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
failtlvtype, failtlvpos, explanation);
}

/* If we have and can decode invstring, we extract destination for listsendpays */
if (invstring) {
struct bolt11 *b11;
char *fail;

b11 = bolt11_decode(cmd, invstring, NULL, NULL, NULL, &fail);
if (b11) {
destination = &b11->receiver_id;
} else {
struct tlv_invoice *b12;

b12 = invoice_decode(cmd, invstring, strlen(invstring),
NULL, NULL, &fail);
if (b12 && b12->invoice_node_id) {
destination = tal(cmd, struct node_id);
node_id_from_pubkey(destination, b12->invoice_node_id);
} else
destination = NULL;
}
} else
destination = NULL;

if (payload->final) {
struct selfpay *selfpay;

Expand All @@ -1944,7 +1968,8 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
*partid, *groupid,
*destination_msat, *msat, AMOUNT_MSAT(0),
label, invstring, local_invreq_id,
&shared_secret);
&shared_secret,
destination);

/* Mark it pending now, though htlc_set_add might
* not resolve immediately */
Expand Down Expand Up @@ -2058,7 +2083,8 @@ static struct command_result *json_injectpaymentonion(struct command *cmd,
*partid, *groupid,
*destination_msat, *msat, AMOUNT_MSAT(0),
label, invstring, local_invreq_id,
&shared_secret);
&shared_secret,
destination);

/* If unknown, we set this equal (so accounting logs 0 fees) */
if (amount_msat_eq(*destination_msat, AMOUNT_MSAT(0)))
Expand Down
20 changes: 16 additions & 4 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -6210,6 +6210,8 @@ def test_injectpaymentonion_3hop(node_factory, executor):
assert lsp['payment_hash'] == inv3['payment_hash']
assert lsp['status'] == 'complete'
assert lsp['amount_msat'] == 1000
# We didn't give it an invstring, so it doesn't know destination
assert 'destination' not in lsp


def test_injectpaymentonion_selfpay(node_factory, executor):
Expand All @@ -6227,6 +6229,7 @@ def test_injectpaymentonion_selfpay(node_factory, executor):

ret = l1.rpc.injectpaymentonion(onion=onion['onion'],
payment_hash=inv4['payment_hash'],
invstring=inv4['bolt11'],
amount_msat=1000,
cltv_expiry=blockheight + 18,
partid=1,
Expand All @@ -6238,6 +6241,7 @@ def test_injectpaymentonion_selfpay(node_factory, executor):
assert lsp['partid'] == 1
assert lsp['payment_hash'] == inv4['payment_hash']
assert lsp['status'] == 'complete'
assert lsp['destination'] == l1.info['id']

# Test self-pay with MPP.
inv5 = l1.rpc.invoice(1000, "test_injectpaymentonion5", "test_injectpaymentonion5")
Expand Down Expand Up @@ -6278,6 +6282,7 @@ def test_injectpaymentonion_selfpay(node_factory, executor):
assert lsp['partid'] == 1 or lsp['partid'] == 2
assert lsp['payment_hash'] == inv5['payment_hash']
assert lsp['status'] == 'complete'
assert 'destination' not in lsp
assert len(lsps) == 2

# Check listpays gives a reasonable result!
Expand Down Expand Up @@ -6362,7 +6367,8 @@ def test_injectpaymentonion_selfpay(node_factory, executor):
amount_msat=1000,
cltv_expiry=blockheight + 18,
partid=1,
groupid=0)
groupid=0,
invstring=inv10['invoice'])
assert sha256(bytes.fromhex(ret['payment_preimage'])).hexdigest() == decoded['invoice_payment_hash']
# The label for the invoice is deterministic.
label = f"{decoded['offer_id']}-{decoded['invreq_payer_id']}-0"
Expand All @@ -6372,6 +6378,7 @@ def test_injectpaymentonion_selfpay(node_factory, executor):
assert lsp['partid'] == 1
assert lsp['payment_hash'] == inv4['payment_hash']
assert lsp['status'] == 'complete'
assert lsp['destination'] == l1.info['id']


def test_injectpaymentonion_blindedpath(node_factory, executor):
Expand Down Expand Up @@ -6440,7 +6447,8 @@ def test_injectpaymentonion_blindedpath(node_factory, executor):
amount_msat=1000,
cltv_expiry=blockheight + 18 + 6,
partid=1,
groupid=0)
groupid=0,
invstring=inv7['invoice'])
assert sha256(bytes.fromhex(ret['payment_preimage'])).hexdigest() == decoded['invoice_payment_hash']
# The label for l2's invoice is deterministic.
label = f"{decoded['offer_id']}-{decoded['invreq_payer_id']}-0"
Expand Down Expand Up @@ -6492,7 +6500,8 @@ def test_injectpaymentonion_blindedpath(node_factory, executor):
amount_msat=1001,
cltv_expiry=blockheight + 18 + 6,
partid=1,
groupid=0)
groupid=0,
invstring=inv8['invoice'])
assert sha256(bytes.fromhex(ret['payment_preimage'])).hexdigest() == decoded['invoice_payment_hash']
# The label for l4's invoice is deterministic.
label = f"{decoded['offer_id']}-{decoded['invreq_payer_id']}-0"
Expand All @@ -6502,6 +6511,7 @@ def test_injectpaymentonion_blindedpath(node_factory, executor):
assert lsp['partid'] == 1
assert lsp['payment_hash'] == decoded['invoice_payment_hash']
assert lsp['status'] == 'complete'
assert lsp['destination'] == decoded['invoice_node_id']

# Finally, with blinded path which starts with us.
offer = l4.rpc.offer('any')
Expand Down Expand Up @@ -6535,7 +6545,8 @@ def test_injectpaymentonion_blindedpath(node_factory, executor):
amount_msat=1001,
cltv_expiry=blockheight + 18 + 6,
partid=1,
groupid=0)
groupid=0,
invstring=inv9['invoice'])
assert sha256(bytes.fromhex(ret['payment_preimage'])).hexdigest() == decoded['invoice_payment_hash']
# The label for the invoice is deterministic.
label = f"{decoded['offer_id']}-{decoded['invreq_payer_id']}-0"
Expand All @@ -6545,6 +6556,7 @@ def test_injectpaymentonion_blindedpath(node_factory, executor):
assert lsp['partid'] == 1
assert lsp['payment_hash'] == decoded['invoice_payment_hash']
assert lsp['status'] == 'complete'
assert lsp['destination'] == decoded['invoice_node_id']


def test_injectpaymentonion_failures(node_factory, executor):
Expand Down

0 comments on commit dc6a5f8

Please sign in to comment.