Skip to content

Commit

Permalink
lightningd: make sendpay support blinding and enctlv fields (EXPE…
Browse files Browse the repository at this point in the history
…RIMENTAL)

This is what actually lets us pay blinded invoices.

Unfortunately, our internal logic assumes every hop in a path has a
next `short_channel_id`, so we have to use a dummy.  This is
sufficient for testing, however.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Apr 14, 2020
1 parent 23f3a3c commit 1d29228
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 5 deletions.
21 changes: 17 additions & 4 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,9 @@ static struct command_result *param_route_hops(struct command *cmd,
struct node_id *id;
struct short_channel_id *channel;
unsigned *delay, *direction;
enum route_hop_style *style;
struct pubkey *blinding;
u8 *enctlv;
enum route_hop_style *style, default_style;

if (!param(cmd, buffer, t,
/* Only *one* of these is required */
Expand All @@ -1229,8 +1231,9 @@ static struct command_result *param_route_hops(struct command *cmd,
p_opt("delay", param_number, &delay),
p_opt("channel", param_short_channel_id, &channel),
p_opt("direction", param_number, &direction),
p_opt_def("style", param_route_hop_style, &style,
ROUTE_HOP_LEGACY),
p_opt("style", param_route_hop_style, &style),
p_opt("blinding", param_pubkey, &blinding),
p_opt("enctlv", param_bin_from_hex, &enctlv),
NULL))
return command_param_failed();

Expand All @@ -1255,11 +1258,21 @@ static struct command_result *param_route_hops(struct command *cmd,
if (!msat)
msat = amount_msat;

if (blinding || enctlv) {
if (style && *style == ROUTE_HOP_LEGACY)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zi]: Can't have blinding or enctlv with legacy", name, i);
default_style = ROUTE_HOP_TLV;
} else
default_style = ROUTE_HOP_LEGACY;

(*hops)[i].amount = *msat;
(*hops)[i].nodeid = *id;
(*hops)[i].delay = *delay;
(*hops)[i].channel_id = *channel;
(*hops)[i].style = *style;
(*hops)[i].blinding = blinding;
(*hops)[i].enctlv = enctlv;
(*hops)[i].style = style ? *style : default_style;
/* FIXME: Actually ignored by sending code! */
(*hops)[i].direction = direction ? *direction : 0;
}
Expand Down
49 changes: 48 additions & 1 deletion tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pyln.proto.onion import TlvPayload
from utils import (
DEVELOPER, wait_for, only_one, sync_blockheight, SLOW_MACHINE, TIMEOUT,
VALGRIND
VALGRIND, EXPERIMENTAL_FEATURES
)
import copy
import os
Expand All @@ -15,6 +15,7 @@
import re
import string
import struct
import subprocess
import time
import unittest

Expand Down Expand Up @@ -2895,3 +2896,49 @@ def test_reject_invalid_payload(node_factory):

with pytest.raises(RpcError, match=r'WIRE_INVALID_ONION_PAYLOAD'):
l1.rpc.waitsendpay(inv['payment_hash'])


@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Needs blinding args to sendpay")
def test_sendpay_blinding(node_factory):
l1, l2, l3, l4 = node_factory.line_graph(4)

blindedpathtool = os.path.join(os.path.dirname(__file__), "..", "devtools", "blindedpath")

# Create blinded path l2->l4
output = subprocess.check_output(
[blindedpathtool, '--simple-output', 'create',
l2.info['id'] + "/" + l2.get_channel_scid(l3),
l3.info['id'] + "/" + l3.get_channel_scid(l4),
l4.info['id']]
).decode('ASCII').strip()

# First line is blinding, then <peerid> then <encblob>.
blinding, p1, p1enc, p2, p2enc, p3 = output.split('\n')
# First hop can't be blinded!
assert p1 == l2.info['id']

amt = 10**3
inv = l4.rpc.invoice(amt, "lbl", "desc")

route = [{'id': l2.info['id'],
'channel': l1.get_channel_scid(l2),
'amount_msat': Millisatoshi(1002),
'delay': 21,
'blinding': blinding,
'enctlv': p1enc},
{'id': p2,
'amount_msat': Millisatoshi(1001),
'delay': 15,
# FIXME: this is a dummy!
'channel': '0x0x0',
'enctlv': p2enc},
{'id': p3,
# FIXME: this is a dummy!
'channel': '0x0x0',
'amount_msat': Millisatoshi(1000),
'delay': 9,
'style': 'tlv'}]
l1.rpc.sendpay(route=route,
payment_hash=inv['payment_hash'],
bolt11=inv['bolt11'])
l1.rpc.waitsendpay(inv['payment_hash'])

0 comments on commit 1d29228

Please sign in to comment.