Skip to content

Commit c415feb

Browse files
Lagrang3rustyrussell
authored andcommitted
lightningd: add option dev-strict-forwarding
Changelog-Add: add option dev-strict-forwarding
1 parent dd956e2 commit c415feb

File tree

5 files changed

+122
-1
lines changed

5 files changed

+122
-1
lines changed

lightningd/lightningd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
151151
ld->dev_hsmd_no_preapprove_check = false;
152152
ld->dev_hsmd_fail_preapprove = false;
153153
ld->dev_handshake_no_reply = false;
154+
ld->dev_strict_forwarding = false;
154155

155156
/*~ We try to ensure enough fds for twice the number of channels
156157
* we start with. We have a developer option to change that factor

lightningd/lightningd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ struct lightningd {
362362
/* Tell connectd not to talk after handshake */
363363
bool dev_handshake_no_reply;
364364

365+
/* Remove the freedom to choose select between parallel channels to
366+
* forward a payment. */
367+
bool dev_strict_forwarding;
368+
365369
/* tor support */
366370
struct wireaddr *proxyaddr;
367371
bool always_use_proxy;

lightningd/options.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,10 @@ static void dev_register_opts(struct lightningd *ld)
956956
opt_set_bool,
957957
&ld->dev_handshake_no_reply,
958958
"Don't send or read init message after connection");
959+
clnopt_noarg("--dev-strict-forwarding", OPT_DEV,
960+
opt_set_bool,
961+
&ld->dev_strict_forwarding,
962+
"Forward HTLCs along the channel specified");
959963
clnopt_noarg("--dev-throttle-gossip", OPT_DEV,
960964
opt_set_bool,
961965
&ld->dev_throttle_gossip,

lightningd/peer_htlcs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,11 @@ static struct channel_id *calc_forwarding_channel(struct lightningd *ld,
12881288
c = NULL;
12891289
}
12901290

1291-
best = best_channel(ld, peer, p->amt_to_forward, c);
1291+
if (!ld->dev_strict_forwarding)
1292+
best = best_channel(ld, peer, p->amt_to_forward, c);
1293+
else
1294+
best = c;
1295+
12921296
if (!c) {
12931297
if (!best)
12941298
return NULL;

tests/test_pay.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6586,3 +6586,111 @@ def test_injectpaymentonion_failures(node_factory, executor):
65866586
# PAY_INJECTPAYMENTONION_FAILED
65876587
assert err.value.error['code'] == 218
65886588
assert 'onionreply' in err.value.error['data']
6589+
6590+
6591+
def test_parallel_channels_reserve(node_factory, bitcoind):
6592+
"""Tests wether we are able to pay through parallel channels concurrently.
6593+
To do that we need to enable strict-forwarding."""
6594+
6595+
def direction(node1, node2):
6596+
return 0 if node1.info["id"] < node2.info["id"] else 1
6597+
6598+
def get_local_channel_by_id(node, chanid):
6599+
peerchannels = node.rpc.listpeerchannels()["channels"]
6600+
if not peerchannels:
6601+
return None
6602+
for c in peerchannels:
6603+
if c["channel_id"] == chanid:
6604+
return c
6605+
return None
6606+
6607+
opts = {
6608+
"fee-base": 0,
6609+
"fee-per-satoshi": 0,
6610+
"cltv-delta": 6,
6611+
"dev-strict-forwarding": None,
6612+
}
6613+
l1, l2, l3 = node_factory.get_nodes(3, opts=opts)
6614+
6615+
l1.fundwallet(10**7)
6616+
l2.fundwallet(10**7)
6617+
6618+
scids = []
6619+
6620+
l1.rpc.connect(l2.info["id"], "localhost", l2.port)
6621+
l2.rpc.connect(l3.info["id"], "localhost", l3.port)
6622+
6623+
c12 = l1.rpc.fundchannel(l2.info["id"], 3000_000, minconf=0)["channel_id"]
6624+
6625+
c23 = []
6626+
c23.append(l2.rpc.fundchannel(l3.info["id"], 1000_000, minconf=0)["channel_id"])
6627+
c23.append(l2.rpc.fundchannel(l3.info["id"], 2000_000, minconf=0)["channel_id"])
6628+
6629+
bitcoind.generate_block(6)
6630+
sync_blockheight(bitcoind, [l1, l2, l3])
6631+
6632+
scids.append(get_local_channel_by_id(l1, c12)["short_channel_id"])
6633+
scids.append(get_local_channel_by_id(l2, c23[0])["short_channel_id"])
6634+
scids.append(get_local_channel_by_id(l2, c23[1])["short_channel_id"])
6635+
6636+
for l in [l1, l2, l3]:
6637+
for c in scids:
6638+
l.wait_channel_active(c)
6639+
6640+
# we should be able to send these two parts:
6641+
nparts = 2
6642+
route_amounts = ["750000sat", "1750000sat"]
6643+
total_msat = sum([Millisatoshi(a) for a in route_amounts[:nparts]])
6644+
6645+
# Test succeeds if we are able to pay this invoice
6646+
inv = l3.rpc.call(
6647+
"invoice",
6648+
{"amount_msat": total_msat, "label": "inv", "description": "inv", "cltv": 10},
6649+
)
6650+
6651+
# Share data by every route we will construct: l1->l2->l3
6652+
route = [
6653+
{
6654+
"id": l2.info["id"],
6655+
"direction": direction(l1, l2),
6656+
"delay": 16,
6657+
"style": "tlv",
6658+
},
6659+
{
6660+
"id": l3.info["id"],
6661+
"direction": direction(l2, l3),
6662+
"delay": 10,
6663+
"style": "tlv",
6664+
},
6665+
]
6666+
6667+
# Send every part with sendpay
6668+
for part in range(nparts):
6669+
this_part_msat = Millisatoshi(route_amounts[part])
6670+
chan1 = get_local_channel_by_id(l1, c12)
6671+
chan2 = get_local_channel_by_id(l2, c23[part])
6672+
6673+
route[0]["channel"] = chan1["short_channel_id"]
6674+
route[1]["channel"] = chan2["short_channel_id"]
6675+
route[0]["amount_msat"] = route[1]["amount_msat"] = this_part_msat
6676+
6677+
assert chan1["spendable_msat"] >= this_part_msat
6678+
assert chan2["spendable_msat"] >= this_part_msat
6679+
6680+
l1.rpc.call(
6681+
"sendpay",
6682+
{
6683+
"route": route,
6684+
"payment_hash": inv["payment_hash"],
6685+
"payment_secret": inv["payment_secret"],
6686+
"amount_msat": total_msat,
6687+
"groupid": 1,
6688+
"partid": part + 1,
6689+
},
6690+
)
6691+
l1.wait_for_htlcs()
6692+
6693+
# Are we happy?
6694+
receipt = only_one(l3.rpc.listinvoices("inv")["invoices"])
6695+
assert receipt["status"] == "paid"
6696+
assert receipt["amount_received_msat"] == total_msat

0 commit comments

Comments
 (0)