Skip to content

Commit f9e28b9

Browse files
s373nZcdecker
authored andcommitted
keysend: Add maxfee to keysend for consistency with pay. ([#7227])
Changelog-Added: keysend: Add `maxfee` to keysend for consistency with pay. ([#7227])
1 parent c7189f6 commit f9e28b9

File tree

11 files changed

+789
-707
lines changed

11 files changed

+789
-707
lines changed

.msggen.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,7 @@
15211521
"KeySend.extratlvs": 9,
15221522
"KeySend.label": 3,
15231523
"KeySend.maxdelay": 6,
1524+
"KeySend.maxfee": 11,
15241525
"KeySend.maxfeepercent": 4,
15251526
"KeySend.msatoshi": 2,
15261527
"KeySend.retry_for": 5,
@@ -6362,6 +6363,10 @@
63626363
"added": "pre-v0.10.1",
63636364
"deprecated": null
63646365
},
6366+
"KeySend.maxfee": {
6367+
"added": "v24.11",
6368+
"deprecated": null
6369+
},
63656370
"KeySend.maxfeepercent": {
63666371
"added": "pre-v0.10.1",
63676372
"deprecated": null

cln-grpc/proto/node.proto

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-grpc/src/convert.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-grpc/src/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ fn test_keysend() {
293293
}],
294294
}),
295295
extratlvs: None,
296+
maxfee: None
296297
};
297298

298299
let u: cln_rpc::model::requests::KeysendRequest = g.into();

cln-rpc/src/model.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/msggen/msggen/schema.json

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15420,6 +15420,13 @@
1542015420
"description": [
1542115421
"Dictionary of additional fields to insert into the final tlv. The format is 'fieldnumber': 'hexstring'."
1542215422
]
15423+
},
15424+
"maxfee": {
15425+
"added": "v24.11",
15426+
"type": "msat",
15427+
"description": [
15428+
"*maxfee* overrides both *maxfeepercent* and *exemptfee* defaults (and if you specify *maxfee* you cannot specify either of those), and creates an absolute limit on what fee we will pay. This allows you to implement your own heuristics rather than the primitive ones used here."
15429+
]
1542315430
}
1542415431
}
1542515432
},
@@ -15552,12 +15559,12 @@
1555215559
},
1555315560
"response": {
1555415561
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
15555-
"payment_hash": "80ff407792947a23f193f9a1968e9a437b071364ae3159f83631335c9a453c1b",
15556-
"created_at": 1722303677.1300898,
15562+
"payment_hash": "bf2806c76e67fbc07bccd878a2c583664f97ba49eebb707939bacaa9d6813858",
15563+
"created_at": 1726169170.7366238,
1555715564
"parts": 1,
1555815565
"amount_msat": 10000,
1555915566
"amount_sent_msat": 10001,
15560-
"payment_preimage": "0d802c9c611bae611d51afa8ddf396df8ba4e0580a2eccfd1120da97e70482a0",
15567+
"payment_preimage": "8e9f92f7f4928fde1469b199680aa09ca2690fa4e1c0b21ea60fd87e962ecce4",
1556115568
"status": "complete"
1556215569
}
1556315570
},
@@ -15576,12 +15583,12 @@
1557615583
},
1557715584
"response": {
1557815585
"destination": "0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199",
15579-
"payment_hash": "3b80a3028343b16f8ab7261343eae40ff73ba833b0b7d4dcbfd42a3078dc322b",
15580-
"created_at": 1722303679.3164163,
15586+
"payment_hash": "06f861fa426d342ca144785243c44093654ff8dfc7cec7db346286c20010cffc",
15587+
"created_at": 1726169172.886992,
1558115588
"parts": 1,
1558215589
"amount_msat": 10000000,
1558315590
"amount_sent_msat": 10000202,
15584-
"payment_preimage": "f76d6b7ef362f33e25eb5571e616f6e539a2c77caf0afa4227d1351546823664",
15591+
"payment_preimage": "9416f0889f0dfe6316e047aee01a5451e29753a51b10ddda83fe6b8ccad2eb72",
1558515592
"status": "complete"
1558615593
}
1558715594
},
@@ -15595,7 +15602,7 @@
1559515602
"routehints": [
1559615603
[
1559715604
{
15598-
"scid": "6250403x3681116x19863",
15605+
"scid": "6974878x14919575x17443",
1559915606
"id": "022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59",
1560015607
"feebase": "1msat",
1560115608
"feeprop": 10,
@@ -15607,12 +15614,12 @@
1560715614
},
1560815615
"response": {
1560915616
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
15610-
"payment_hash": "0458c01fdd3aa0b9829002390301f92083e78dc27bb293bc3e7caee5d4ed7259",
15611-
"created_at": 1722303682.5805738,
15617+
"payment_hash": "c9e6b85aafb27fbaceb3f0eca6d0940d6e1d93a4be2d6da981aed9503fcec92c",
15618+
"created_at": 1726169175.977477,
1561215619
"parts": 2,
1561315620
"amount_msat": 10000,
1561415621
"amount_sent_msat": 10001,
15615-
"payment_preimage": "4dad6dcf625f650a35a8199fbda18ea4f6717cdfadb40e6bed2bf5f96a4742b0",
15622+
"payment_preimage": "1cd3749122f3a1b8c1cbd9f4585ec820ec4e1b8f2aa3514a4dd9deda170bdf5d",
1561615623
"status": "complete"
1561715624
}
1561815625
}

contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

Lines changed: 674 additions & 674 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/schemas/lightning-keysend.json

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@
103103
"description": [
104104
"Dictionary of additional fields to insert into the final tlv. The format is 'fieldnumber': 'hexstring'."
105105
]
106+
},
107+
"maxfee": {
108+
"added": "v24.11",
109+
"type": "msat",
110+
"description": [
111+
"*maxfee* overrides both *maxfeepercent* and *exemptfee* defaults (and if you specify *maxfee* you cannot specify either of those), and creates an absolute limit on what fee we will pay. This allows you to implement your own heuristics rather than the primitive ones used here."
112+
]
106113
}
107114
}
108115
},
@@ -235,12 +242,12 @@
235242
},
236243
"response": {
237244
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
238-
"payment_hash": "80ff407792947a23f193f9a1968e9a437b071364ae3159f83631335c9a453c1b",
239-
"created_at": 1722303677.1300898,
245+
"payment_hash": "bf2806c76e67fbc07bccd878a2c583664f97ba49eebb707939bacaa9d6813858",
246+
"created_at": 1726169170.7366238,
240247
"parts": 1,
241248
"amount_msat": 10000,
242249
"amount_sent_msat": 10001,
243-
"payment_preimage": "0d802c9c611bae611d51afa8ddf396df8ba4e0580a2eccfd1120da97e70482a0",
250+
"payment_preimage": "8e9f92f7f4928fde1469b199680aa09ca2690fa4e1c0b21ea60fd87e962ecce4",
244251
"status": "complete"
245252
}
246253
},
@@ -259,12 +266,12 @@
259266
},
260267
"response": {
261268
"destination": "0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199",
262-
"payment_hash": "3b80a3028343b16f8ab7261343eae40ff73ba833b0b7d4dcbfd42a3078dc322b",
263-
"created_at": 1722303679.3164163,
269+
"payment_hash": "06f861fa426d342ca144785243c44093654ff8dfc7cec7db346286c20010cffc",
270+
"created_at": 1726169172.886992,
264271
"parts": 1,
265272
"amount_msat": 10000000,
266273
"amount_sent_msat": 10000202,
267-
"payment_preimage": "f76d6b7ef362f33e25eb5571e616f6e539a2c77caf0afa4227d1351546823664",
274+
"payment_preimage": "9416f0889f0dfe6316e047aee01a5451e29753a51b10ddda83fe6b8ccad2eb72",
268275
"status": "complete"
269276
}
270277
},
@@ -278,7 +285,7 @@
278285
"routehints": [
279286
[
280287
{
281-
"scid": "6250403x3681116x19863",
288+
"scid": "6974878x14919575x17443",
282289
"id": "022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59",
283290
"feebase": "1msat",
284291
"feeprop": 10,
@@ -290,12 +297,12 @@
290297
},
291298
"response": {
292299
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
293-
"payment_hash": "0458c01fdd3aa0b9829002390301f92083e78dc27bb293bc3e7caee5d4ed7259",
294-
"created_at": 1722303682.5805738,
300+
"payment_hash": "c9e6b85aafb27fbaceb3f0eca6d0940d6e1d93a4be2d6da981aed9503fcec92c",
301+
"created_at": 1726169175.977477,
295302
"parts": 2,
296303
"amount_msat": 10000,
297304
"amount_sent_msat": 10001,
298-
"payment_preimage": "4dad6dcf625f650a35a8199fbda18ea4f6717cdfadb40e6bed2bf5f96a4742b0",
305+
"payment_preimage": "1cd3749122f3a1b8c1cbd9f4585ec820ec4e1b8f2aa3514a4dd9deda170bdf5d",
299306
"status": "complete"
300307
}
301308
}

plugins/keysend.c

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static struct channel_hint_set *global_hints;
2424
* ================
2525
*
2626
* The keysend modifier adds the payment preimage to the TLV payload. This
27-
* enables the recipient to accept the payment despite it not correspondin to
27+
* enables the recipient to accept the payment despite it not corresponding to
2828
* an invoice that the recipient created. Keysend does not provide any proof
2929
* or payment, but does not require an out-of-band communication round to get
3030
* an invoice first.
@@ -218,7 +218,7 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
218218
{
219219
struct payment *p;
220220
const char *label;
221-
struct amount_msat *exemptfee, *msat;
221+
struct amount_msat *exemptfee, *msat, *maxfee;
222222
struct node_id *destination;
223223
u64 *maxfee_pct_millionths;
224224
u32 *maxdelay;
@@ -232,14 +232,15 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
232232
p_req("destination", param_node_id, &destination),
233233
p_req("amount_msat", param_msat, &msat),
234234
p_opt("label", param_string, &label),
235-
p_opt_def("maxfeepercent", param_millionths,
236-
&maxfee_pct_millionths, 500000),
235+
p_opt("maxfeepercent", param_millionths,
236+
&maxfee_pct_millionths),
237237
p_opt_def("retry_for", param_number, &retryfor, 60),
238238
p_opt_def("maxdelay", param_number, &maxdelay,
239239
maxdelay_default),
240-
p_opt_def("exemptfee", param_msat, &exemptfee, AMOUNT_MSAT(5000)),
240+
p_opt("exemptfee", param_msat, &exemptfee),
241241
p_opt("extratlvs", param_extra_tlvs, &extra_fields),
242242
p_opt("routehints", param_routehint_array, &hints),
243+
p_opt("maxfee", param_msat, &maxfee),
243244
p_opt_dev("dev_use_shadow", param_bool, &dev_use_shadow, true),
244245
NULL))
245246
return command_param_failed();
@@ -275,19 +276,36 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
275276
"We are the destination. Keysend cannot be used to send funds to yourself");
276277
}
277278

278-
if (!amount_msat_fee(&p->constraints.fee_budget, p->our_amount, 0,
279-
*maxfee_pct_millionths / 100)) {
280-
return command_fail(
281-
cmd, JSONRPC2_INVALID_PARAMS,
282-
"Overflow when computing fee budget, fee rate too high.");
283-
}
284-
285279
p->constraints.cltv_budget = *maxdelay;
286280

287281
payment_mod_keysend_get_data(p)->extra_tlvs =
288282
tal_steal(p, extra_fields);
289283

290-
payment_mod_exemptfee_get_data(p)->amount = *exemptfee;
284+
if (maxfee) {
285+
if (maxfee_pct_millionths || exemptfee) {
286+
return command_fail(
287+
cmd, JSONRPC2_INVALID_PARAMS,
288+
"If you specify maxfee, cannot specify maxfeepercent or exemptfee.");
289+
}
290+
p->constraints.fee_budget = *maxfee;
291+
payment_mod_exemptfee_get_data(p)->amount = AMOUNT_MSAT(0);
292+
} else {
293+
u64 maxppm;
294+
295+
if (maxfee_pct_millionths)
296+
maxppm = *maxfee_pct_millionths / 100;
297+
else
298+
maxppm = 500000 / 100;
299+
if (!amount_msat_fee(&p->constraints.fee_budget, p->our_amount, 0,
300+
maxppm)) {
301+
return command_fail(
302+
cmd, JSONRPC2_INVALID_PARAMS,
303+
"Overflow when computing fee budget, fee rate too high.");
304+
}
305+
payment_mod_exemptfee_get_data(p)->amount
306+
= exemptfee ? *exemptfee : AMOUNT_MSAT(5000);
307+
}
308+
291309
payment_mod_shadowroute_get_data(p)->use_shadow = *dev_use_shadow;
292310
p->label = tal_steal(p, label);
293311

tests/test_pay.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,6 +3679,31 @@ def test_keysend_routehint(node_factory):
36793679
assert(inv['amount_received_msat'] >= Millisatoshi(amt))
36803680

36813681

3682+
def test_keysend_maxfee(node_factory):
3683+
l1, l2, l3 = node_factory.line_graph(
3684+
3,
3685+
wait_for_announce=True,
3686+
opts=[{}, {'fee-base': 50, 'fee-per-satoshi': 0}, {}]
3687+
)
3688+
3689+
# We should fail because maxfee and exemptfee cannot be set simultaneously.
3690+
with pytest.raises(RpcError):
3691+
l1.rpc.call("keysend", payload={'destination': l3.info['id'], 'amount_msat': 1, 'maxfee': 1, 'exemptfee': 5000})
3692+
3693+
# We should fail because maxfee and maxfeepercent cannot be set simultaneously.
3694+
with pytest.raises(RpcError):
3695+
l1.rpc.call("keysend", payload={'destination': l3.info['id'], 'amount_msat': 1, 'maxfee': 1, 'maxfeepercent': 0.0001})
3696+
3697+
# We should fail because 50msat base fee on l2 exceeds maxfee of 1msat.
3698+
with pytest.raises(RpcError):
3699+
l1.rpc.call("keysend", payload={'destination': l3.info['id'], 'amount_msat': 1, 'maxfee': 1})
3700+
assert len(l3.rpc.listinvoices()['invoices']) == 0
3701+
3702+
# Perform a normal keysend with maxfee.
3703+
l1.rpc.call("keysend", payload={'destination': l3.info['id'], 'amount_msat': 1, 'maxfee': 50})
3704+
assert len(l3.rpc.listinvoices()['invoices']) == 1
3705+
3706+
36823707
def test_invalid_onion_channel_update(node_factory):
36833708
'''
36843709
Some onion failures "should" send a `channel_update`.

0 commit comments

Comments
 (0)