Browse Source

pay: Fix logic of the intereface `find_worst_channel`

travis-debug
trueptolemy 5 years ago
committed by Christian Decker
parent
commit
c737fa6b91
  1. 27
      plugins/pay.c
  2. 12
      tests/test_pay.py

27
plugins/pay.c

@ -494,22 +494,31 @@ static struct command_result *sendpay_error(struct command *cmd,
static const jsmntok_t *find_worst_channel(const char *buf, static const jsmntok_t *find_worst_channel(const char *buf,
const jsmntok_t *route, const jsmntok_t *route,
const char *fieldname, const char *fieldname)
u64 final)
{ {
u64 prev = final, worstval = 0; u64 prev, worstval = 0;
const jsmntok_t *worst = NULL, *t; const jsmntok_t *worst = NULL, *t, *t_prev = NULL;
size_t i; size_t i;
json_for_each_arr(i, t, route) { json_for_each_arr(i, t, route) {
u64 val; u64 val;
json_to_u64(buf, json_get_member(buf, t, fieldname), &val); json_to_u64(buf, json_get_member(buf, t, fieldname), &val);
if (worst == NULL || val - prev > worstval) {
worst = t; /* For the first hop, now we can't know if it's the worst.
worstval = val - prev; * Just store the info and continue. */
if (!i) {
prev = val;
t_prev = t;
continue;
}
if (worst == NULL || prev - val > worstval) {
worst = t_prev;
worstval = prev - val;
} }
prev = val; prev = val;
t_prev = t;
} }
return worst; return worst;
@ -606,7 +615,7 @@ static struct command_result *getroute_done(struct command *cmd,
/* Try excluding most fee-charging channel (unless it's in /* Try excluding most fee-charging channel (unless it's in
* routeboost). */ * routeboost). */
charger = find_worst_channel(buf, t, "msatoshi", pc->msat.millisatoshis); /* Raw: shared function needs u64 */ charger = find_worst_channel(buf, t, "msatoshi");
if (maybe_exclude(pc, buf, charger)) { if (maybe_exclude(pc, buf, charger)) {
return start_pay_attempt(cmd, pc, return start_pay_attempt(cmd, pc,
"Excluded expensive channel %s", "Excluded expensive channel %s",
@ -633,7 +642,7 @@ static struct command_result *getroute_done(struct command *cmd,
else else
tal_free(failed); tal_free(failed);
delayer = find_worst_channel(buf, t, "delay", pc->final_cltv); delayer = find_worst_channel(buf, t, "delay");
/* Try excluding most delaying channel (unless it's in /* Try excluding most delaying channel (unless it's in
* routeboost). */ * routeboost). */

12
tests/test_pay.py

@ -94,25 +94,29 @@ def test_pay_limits(node_factory):
assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE
# It should have retried (once without routehint, too) # It should have retried two more times (one without routehint and one with routehint)
status = l1.rpc.call('paystatus', {'bolt11': inv['bolt11']})['pay'][0]['attempts'] status = l1.rpc.call('paystatus', {'bolt11': inv['bolt11']})['pay'][0]['attempts']
# Excludes channel, then ignores routehint which includes that, then # Excludes channel, then ignores routehint which includes that, then
# it excludes other channel. # it excludes other channel.
assert len(status) == 2 assert len(status) == 3
assert status[0]['strategy'] == "Initial attempt" assert status[0]['strategy'] == "Initial attempt"
# Exclude the channel l1->l2
assert status[1]['strategy'].startswith("Excluded expensive channel ") assert status[1]['strategy'].startswith("Excluded expensive channel ")
# With the routehint
assert status[2]['strategy'].startswith("Trying route hint")
# Delay too high. # Delay too high.
with pytest.raises(RpcError, match=r'Route wanted delay of .* blocks') as err: with pytest.raises(RpcError, match=r'Route wanted delay of .* blocks') as err:
l1.rpc.call('pay', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxdelay': 0}) l1.rpc.call('pay', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxdelay': 0})
assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE assert err.value.error['code'] == PAY_ROUTE_TOO_EXPENSIVE
# Should also have retried. # Should also have retried two more times.
status = l1.rpc.call('paystatus', {'bolt11': inv['bolt11']})['pay'][1]['attempts'] status = l1.rpc.call('paystatus', {'bolt11': inv['bolt11']})['pay'][1]['attempts']
assert len(status) == 2 assert len(status) == 3
assert status[0]['strategy'] == "Initial attempt" assert status[0]['strategy'] == "Initial attempt"
assert status[1]['strategy'].startswith("Excluded delaying channel ") assert status[1]['strategy'].startswith("Excluded delaying channel ")
assert status[2]['strategy'].startswith("Trying route hint")
# This works, because fee is less than exemptfee. # This works, because fee is less than exemptfee.
l1.rpc.call('pay', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxfeepercent': 0.0001, 'exemptfee': 2000}) l1.rpc.call('pay', {'bolt11': inv['bolt11'], 'msatoshi': 100000, 'maxfeepercent': 0.0001, 'exemptfee': 2000})

Loading…
Cancel
Save