lightningd: make sendpay support blinding and enctlv fields (EXPERIMENTAL)

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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2020-04-11 12:54:26 +09:30
parent 23f3a3c840
commit 1d29228136
2 changed files with 65 additions and 5 deletions

View File

@ -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 */
@ -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();
@ -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;
}

View File

@ -6,7 +6,7 @@ from pyln.client import RpcError, Millisatoshi
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
@ -15,6 +15,7 @@ import random
import re
import string
import struct
import subprocess
import time
import unittest
@ -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'])