mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
plugins/pay: implement maxfeepercent, maxdelay and exemptfee.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
c6fa993203
commit
a8f2f28c72
@ -19,6 +19,11 @@ struct pay_command {
|
||||
u64 msatoshi;
|
||||
double riskfactor;
|
||||
|
||||
/* Limits on what routes we'll accept. */
|
||||
double maxfeepercent;
|
||||
unsigned int maxdelay;
|
||||
u64 exemptfee;
|
||||
|
||||
/* Payment hash, as text. */
|
||||
const char *payment_hash;
|
||||
|
||||
@ -121,10 +126,40 @@ static struct command_result *getroute_done(struct command *cmd,
|
||||
struct pay_attempt attempt;
|
||||
const jsmntok_t *t = json_get_member(buf, result, "route");
|
||||
char *json_desc;
|
||||
u64 fee;
|
||||
u32 delay;
|
||||
double feepercent;
|
||||
|
||||
if (!t)
|
||||
plugin_err("getroute gave no 'route'? '%.*s'",
|
||||
result->end - result->start, buf);
|
||||
|
||||
if (!json_to_u64(buf, json_delve(buf, t, "[0].msatoshi"), &fee))
|
||||
plugin_err("getroute with invalid msatoshi? '%.*s'",
|
||||
result->end - result->start, buf);
|
||||
fee -= pc->msatoshi;
|
||||
|
||||
if (!json_to_number(buf, json_delve(buf, t, "[0].delay"), &delay))
|
||||
plugin_err("getroute with invalid delay? '%.*s'",
|
||||
result->end - result->start, buf);
|
||||
|
||||
/* Casting u64 to double will lose some precision. The loss of precision
|
||||
* in feepercent will be like 3.0000..(some dots)..1 % - 3.0 %.
|
||||
* That loss will not be representable in double. So, it's Okay to
|
||||
* cast u64 to double for feepercent calculation. */
|
||||
feepercent = ((double)fee) * 100.0 / ((double) pc->msatoshi);
|
||||
|
||||
if (fee > pc->exemptfee && feepercent > pc->maxfeepercent) {
|
||||
return command_fail(cmd, PAY_ROUTE_TOO_EXPENSIVE,
|
||||
"Route wanted fee of %"PRIu64" msatoshis",
|
||||
fee);
|
||||
}
|
||||
|
||||
if (delay > pc->maxdelay) {
|
||||
return command_fail(cmd, PAY_ROUTE_TOO_EXPENSIVE,
|
||||
"Route wanted delay of %u blocks", delay);
|
||||
}
|
||||
|
||||
attempt.route = json_strdup(pc->attempts, buf, result);
|
||||
tal_arr_expand(&pc->attempts, attempt);
|
||||
|
||||
@ -230,11 +265,9 @@ static struct command_result *handle_pay(struct command *cmd,
|
||||
double *riskfactor;
|
||||
unsigned int *retryfor;
|
||||
struct pay_command *pc = tal(cmd, struct pay_command);
|
||||
|
||||
/* FIXME! */
|
||||
double *maxfeepercent;
|
||||
unsigned int *maxdelay;
|
||||
unsigned int *exemptfee;
|
||||
u64 *exemptfee;
|
||||
|
||||
setup_locale();
|
||||
|
||||
@ -248,7 +281,7 @@ static struct command_result *handle_pay(struct command *cmd,
|
||||
p_opt_def("maxdelay", param_number, &maxdelay,
|
||||
/* FIXME! */
|
||||
14 * 24 * 6),
|
||||
p_opt_def("exemptfee", param_number, &exemptfee, 5000),
|
||||
p_opt_def("exemptfee", param_u64, &exemptfee, 5000),
|
||||
NULL))
|
||||
return NULL;
|
||||
|
||||
@ -276,6 +309,9 @@ static struct command_result *handle_pay(struct command *cmd,
|
||||
pc->msatoshi = *msatoshi;
|
||||
}
|
||||
|
||||
pc->maxfeepercent = *maxfeepercent;
|
||||
pc->maxdelay = *maxdelay;
|
||||
pc->exemptfee = *exemptfee;
|
||||
pc->riskfactor = *riskfactor;
|
||||
pc->dest = type_to_string(cmd, struct pubkey, &b11->receiver_id);
|
||||
pc->payment_hash = type_to_string(pc, struct sha256,
|
||||
|
@ -59,6 +59,31 @@ def test_pay(node_factory):
|
||||
assert len(payments) == 1 and payments[0]['payment_preimage'] == preimage
|
||||
|
||||
|
||||
def test_pay_limits(node_factory):
|
||||
"""Test that we enforce fee max percentage and max delay"""
|
||||
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True)
|
||||
|
||||
# FIXME: pylightning should define these!
|
||||
PAY_ROUTE_TOO_EXPENSIVE = 206
|
||||
|
||||
inv = l3.rpc.invoice("any", "any", 'description')
|
||||
|
||||
# Fee too high.
|
||||
with pytest.raises(RpcError, match=r'Route wanted fee of .* msatoshis') as err:
|
||||
l1.rpc.call('pay2', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxfeepercent': 0.0001, 'exemptfee': 0})
|
||||
|
||||
assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE
|
||||
|
||||
# Delay too high.
|
||||
with pytest.raises(RpcError, match=r'Route wanted delay of .* blocks') as err:
|
||||
l1.rpc.call('pay2', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxdelay': 0})
|
||||
|
||||
assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE
|
||||
|
||||
# This works, because fee is less than exemptfee.
|
||||
l1.rpc.call('pay2', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxfeepercent': 0.0001, 'exemptfee': 2000})
|
||||
|
||||
|
||||
def test_pay0(node_factory):
|
||||
"""Test paying 0 amount
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user