Skip to content

Commit b0a4743

Browse files
committed
pay: Enforce maxdelay for direct channel payments
When paying through a direct channel, direct_pay_override() creates a route bypassing the normal routing path, which skips the CLTV budget check in payment_getroute(). This allows payments to succeed even when maxdelay is set below the required min_final_cltv_expiry. Add a check in direct_pay_override() to verify the required CLTV doesn't exceed cltv_budget before using the direct channel shortcut. If it exceeds, skip the direct channel and let normal routing handle the failure with a proper error message. Fixes: #8609 Changelog-Fixed: pay: `maxdelay` parameter now enforced for direct channel payments
1 parent 22f7a62 commit b0a4743

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

plugins/libplugin-pay.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,6 +3479,15 @@ static struct command_result *direct_pay_override(struct payment *p)
34793479
hint = channel_hint_set_find(root->hints, d->chan);
34803480
if (hint && hint->enabled &&
34813481
amount_msat_greater(hint->estimated_capacity, p->our_amount)) {
3482+
if (p->getroute->cltv > p->constraints.cltv_budget) {
3483+
paymod_log(p, LOG_DBG,
3484+
"Direct channel (%s) skipped: "
3485+
"CLTV delay %u exceeds budget %u.",
3486+
fmt_short_channel_id_dir(tmpctx, &hint->scid),
3487+
p->getroute->cltv, p->constraints.cltv_budget);
3488+
return payment_continue(p);
3489+
}
3490+
34823491
/* Now build a route that consists only of this single hop */
34833492
p->route = tal_arr(p, struct route_hop, 1);
34843493
p->route[0].amount = p->our_amount;

tests/test_pay.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ def test_pay_limits(node_factory):
150150
assert status[0]['strategy'] == "Initial attempt"
151151

152152

153+
def test_pay_maxdelay_direct_channel(node_factory):
154+
"""Test that maxdelay is enforced even for direct channel payments"""
155+
l1, l2 = node_factory.line_graph(2, wait_for_announce=True)
156+
157+
inv = l2.rpc.invoice('10000msat', 'test_pay_maxdelay_direct', 'description')['bolt11']
158+
159+
# Delay too low for direct channel.
160+
with pytest.raises(RpcError, match=r'CLTV delay exceeds our CLTV budget'):
161+
l1.rpc.call('pay', {'bolt11': inv, 'maxdelay': 1})
162+
163+
153164
def test_pay_exclude_node(node_factory, bitcoind):
154165
"""Test excluding the node if there's the NODE-level error in the failure_code
155166
"""

0 commit comments

Comments
 (0)