Skip to content

Commit

Permalink
askrene: fixup
Browse files Browse the repository at this point in the history
Changelog-EXPERIMENTAL: fixup to askrene to compute fees on routes correctly.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
  • Loading branch information
Lagrang3 committed Sep 4, 2024
1 parent 5ec5580 commit b8aaca0
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 13 deletions.
2 changes: 1 addition & 1 deletion plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ static const char *get_routes(const tal_t *ctx,
struct gossmap_node *far_end;
const struct half_chan *h = flow_edge(flows[i], j);

rh->amount = msat;
if (!amount_msat_add_fee(&msat, h->base_fee, h->proportional_fee))
plugin_err(plugin, "Adding fee to amount");
delay += h->delay;
Expand All @@ -390,7 +391,6 @@ static const char *get_routes(const tal_t *ctx,
rh->direction = flows[i]->dirs[j];
far_end = gossmap_nth_node(rq->gossmap, flows[i]->path[j], !flows[i]->dirs[j]);
gossmap_node_get_id(rq->gossmap, far_end, &rh->node_id);
rh->amount = msat;
rh->delay = delay;
}
(*amounts)[i] = flow_delivers(flows[i]);
Expand Down
124 changes: 112 additions & 12 deletions tests/test_askrene.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def test_getroutes(node_factory):
'path': [{'short_channel_id': '0x1x0',
'direction': 1,
'next_node_id': nodemap[1],
'amount_msat': 1010,
'amount_msat': 1000,
'delay': 99 + 6}]}]}
# Two hop, still easy.
assert l1.rpc.getroutes(source=nodemap[0],
Expand All @@ -191,12 +191,12 @@ def test_getroutes(node_factory):
'path': [{'short_channel_id': '0x1x0',
'direction': 1,
'next_node_id': nodemap[1],
'amount_msat': 103020,
'amount_msat': 102000,
'delay': 99 + 6 + 6},
{'short_channel_id': '1x3x2',
'direction': 1,
'next_node_id': nodemap[3],
'amount_msat': 102000,
'amount_msat': 100000,
'delay': 99 + 6}
]}]}

Expand Down Expand Up @@ -237,7 +237,7 @@ def test_getroutes(node_factory):
'path': [{'short_channel_id': '0x2x3',
'direction': 1,
'next_node_id': nodemap[2],
'amount_msat': 1000001,
'amount_msat': 1000000,
'delay': 99 + 6}]}]}

# For 10000 sats, we will split.
Expand All @@ -251,7 +251,7 @@ def test_getroutes(node_factory):
'delay': 99 + 6}],
[{'short_channel_id': '0x2x3',
'next_node_id': nodemap[2],
'amount_msat': 9495009,
'amount_msat': 9495000,
'delay': 99 + 6}]])


Expand Down Expand Up @@ -340,7 +340,7 @@ def test_getroutes_auto_sourcefree(node_factory):
{'short_channel_id': '1x3x2',
'direction': 1,
'next_node_id': nodemap[3],
'amount_msat': 102000,
'amount_msat': 100000,
'delay': 99 + 6}
]}]}

Expand Down Expand Up @@ -401,9 +401,9 @@ def test_getroutes_auto_localchans(node_factory):
100000,
maxfee_msat=100000,
layers=['auto.localchans'],
paths=[[{'short_channel_id': scid12, 'amount_msat': 102012, 'delay': 99 + 6 + 6 + 6},
{'short_channel_id': '0x1x0', 'amount_msat': 102010, 'delay': 99 + 6 + 6},
{'short_channel_id': '1x2x1', 'amount_msat': 101000, 'delay': 99 + 6}]])
paths=[[{'short_channel_id': scid12, 'amount_msat': 102010, 'delay': 99 + 6 + 6 + 6},
{'short_channel_id': '0x1x0', 'amount_msat': 101000, 'delay': 99 + 6 + 6},
{'short_channel_id': '1x2x1', 'amount_msat': 100000, 'delay': 99 + 6}]])

# This should get self-discount correct
check_getroute_paths(l1,
Expand All @@ -412,9 +412,9 @@ def test_getroutes_auto_localchans(node_factory):
100000,
maxfee_msat=100000,
layers=['auto.localchans', 'auto.sourcefree'],
paths=[[{'short_channel_id': scid12, 'amount_msat': 102010, 'delay': 99 + 6 + 6},
{'short_channel_id': '0x1x0', 'amount_msat': 102010, 'delay': 99 + 6 + 6},
{'short_channel_id': '1x2x1', 'amount_msat': 101000, 'delay': 99 + 6}]])
paths=[[{'short_channel_id': scid12, 'amount_msat': 102010, 'delay': 99 + 6 + 6},
{'short_channel_id': '0x1x0', 'amount_msat': 101000, 'delay': 99 + 6 + 6},
{'short_channel_id': '1x2x1', 'amount_msat': 100000, 'delay': 99 + 6}]])


def test_fees_dont_exceed_constraints(node_factory):
Expand Down Expand Up @@ -500,3 +500,103 @@ def test_live_spendable(node_factory, bitcoind):
exceeded[scidd] = f"Path total {path_total[scidd]} > spendable {maxes[scidd]}"

assert exceeded == {}


def test_forwarding_fees(node_factory):
"""Tests if getroutes gets the fees right."""

def fees(amt, propfee, basefee):
return basefee + (amt * propfee) // 1000000

l1 = node_factory.get_node(start=False)

basefee = 7
propfee = 10000
msat = 123000
capacity = 1000000
# 0 has to use two paths (1 and 2) to reach 3. But we tell it 0->1 has limited capacity.
gsfile, nodemap = generate_gossip_store(
[
GenChannel(
0,
1,
capacity_sats=capacity,
forward=GenChannel.Half(propfee=propfee, basefee=basefee),
),
GenChannel(
1,
2,
capacity_sats=capacity,
forward=GenChannel.Half(propfee=propfee, basefee=basefee),
),
GenChannel(
2,
3,
capacity_sats=capacity,
forward=GenChannel.Half(propfee=propfee, basefee=basefee),
),
]
)

# Set up l1 with this as the gossip_store
shutil.copy(
gsfile.name, os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "gossip_store")
)
l1.start()

chan = only_one(
[
c
for c in l1.rpc.listchannels(source=nodemap[0])["channels"]
if c["destination"] == nodemap[1]
]
)

routes = l1.rpc.getroutes(
source=nodemap[0],
destination=nodemap[3],
amount_msat=msat,
layers=["test_layers"],
maxfee_msat=msat,
final_cltv=99,
)["routes"]
assert len(routes) == 1
assert len(routes[0]["path"]) == 3
assert routes[0]["path"][-1]["amount_msat"] >= msat
msat = routes[0]["path"][-1]["amount_msat"]
msat = msat + fees(msat, propfee, basefee)
assert routes[0]["path"][-2]["amount_msat"] == msat
msat = msat + fees(msat, propfee, basefee)
assert routes[0]["path"][-3]["amount_msat"] == msat


def test_forwarding_fees2(node_factory):
"""Make sure we use correct delay and fees for the direction we're going."""

def fees(amt, propfee, basefee):
return basefee + (amt * propfee) // 1000000

l1, l2, l3 = node_factory.line_graph(
3,
wait_for_announce=True,
opts=[
{},
{"fee-base": 2000, "fee-per-satoshi": 20, "cltv-delta": 20},
{"fee-base": 3000, "fee-per-satoshi": 30, "cltv-delta": 30},
],
)
msat = 123000
routes = l1.rpc.getroutes(
source=l1.info["id"],
destination=l3.info["id"],
layers=["auto.localchans"],
maxfee_msat=msat,
amount_msat=msat,
final_cltv=99,
)["routes"]
assert len(routes) == 1
assert len(routes[0]["path"]) == 2
assert routes[0]["path"][-1]["amount_msat"] >= msat
msat = routes[0]["path"][-1]["amount_msat"]
msat = msat + fees(msat, 20, 2000)
assert routes[0]["path"][-2]["amount_msat"] >= msat

0 comments on commit b8aaca0

Please sign in to comment.