Skip to content

Commit fe5da2d

Browse files
committed
askrene: paranoid checks ...
that new flows respect the HTLC min/max constraints. Changelog-None Signed-off-by: Lagrang3 <[email protected]>
1 parent 73f7d9c commit fe5da2d

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

plugins/askrene/mcf.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,89 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
12471247
return NULL;
12481248
}
12491249

1250+
/* Get the scidd for the i'th hop in flow */
1251+
static void get_scidd(const struct gossmap *gossmap, const struct flow *flow,
1252+
size_t i, struct short_channel_id_dir *scidd)
1253+
{
1254+
scidd->scid = gossmap_chan_scid(gossmap, flow->path[i]);
1255+
scidd->dir = flow->dirs[i];
1256+
}
1257+
1258+
/* We use an fp16_t approximatin for htlc_max/min: this gets the exact value. */
1259+
static struct amount_msat
1260+
get_chan_htlc_max(const struct route_query *rq, const struct gossmap_chan *c,
1261+
const struct short_channel_id_dir *scidd)
1262+
{
1263+
struct amount_msat htlc_max;
1264+
1265+
gossmap_chan_get_update_details(rq->gossmap, c, scidd->dir, NULL, NULL,
1266+
NULL, NULL, NULL, NULL, NULL,
1267+
&htlc_max);
1268+
return htlc_max;
1269+
}
1270+
1271+
static struct amount_msat
1272+
get_chan_htlc_min(const struct route_query *rq, const struct gossmap_chan *c,
1273+
const struct short_channel_id_dir *scidd)
1274+
{
1275+
struct amount_msat htlc_min;
1276+
1277+
gossmap_chan_get_update_details(rq->gossmap, c, scidd->dir, NULL, NULL,
1278+
NULL, NULL, NULL, NULL, &htlc_min,
1279+
NULL);
1280+
return htlc_min;
1281+
}
1282+
1283+
static bool check_htlc_min_limits(struct route_query *rq, struct flow **flows)
1284+
{
1285+
1286+
for (size_t k = 0; k < tal_count(flows); k++) {
1287+
struct flow *flow = flows[k];
1288+
size_t pathlen = tal_count(flow->path);
1289+
struct amount_msat hop_amt = flow->delivers;
1290+
for (size_t i = pathlen - 1; i < pathlen; i--) {
1291+
const struct half_chan *h = flow_edge(flow, i);
1292+
struct short_channel_id_dir scidd;
1293+
1294+
get_scidd(rq->gossmap, flow, i, &scidd);
1295+
struct amount_msat htlc_min =
1296+
get_chan_htlc_min(rq, flow->path[i], &scidd);
1297+
if (amount_msat_less(hop_amt, htlc_min))
1298+
return false;
1299+
1300+
if (!amount_msat_add_fee(&hop_amt, h->base_fee,
1301+
h->proportional_fee))
1302+
abort();
1303+
}
1304+
}
1305+
return true;
1306+
}
1307+
1308+
static bool check_htlc_max_limits(struct route_query *rq, struct flow **flows)
1309+
{
1310+
1311+
for (size_t k = 0; k < tal_count(flows); k++) {
1312+
struct flow *flow = flows[k];
1313+
size_t pathlen = tal_count(flow->path);
1314+
struct amount_msat hop_amt = flow->delivers;
1315+
for (size_t i = pathlen - 1; i < pathlen; i--) {
1316+
const struct half_chan *h = flow_edge(flow, i);
1317+
struct short_channel_id_dir scidd;
1318+
1319+
get_scidd(rq->gossmap, flow, i, &scidd);
1320+
struct amount_msat htlc_max =
1321+
get_chan_htlc_max(rq, flow->path[i], &scidd);
1322+
if (amount_msat_greater(hop_amt, htlc_max))
1323+
return false;
1324+
1325+
if (!amount_msat_add_fee(&hop_amt, h->base_fee,
1326+
h->proportional_fee))
1327+
abort();
1328+
}
1329+
}
1330+
return true;
1331+
}
1332+
12501333
/* FIXME: add extra constraint maximum route length, use an activation
12511334
* probability cost for each channel. Recall that every activation cost, eg.
12521335
* base fee and activation probability can only be properly added modifying the
@@ -1333,6 +1416,21 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
13331416
* right now if all_deliver > amount_to_deliver means a bug. */
13341417
assert(amount_msat_greater_eq(amount_to_deliver, all_deliver));
13351418

1419+
/* we should have fixed all htlc violations, "don't trust,
1420+
* verify" */
1421+
if (!check_htlc_min_limits(rq, new_flows)) {
1422+
error_message = rq_log(
1423+
rq, rq, LOG_BROKEN,
1424+
"%s: check_htlc_min_limits failed", __func__);
1425+
goto fail;
1426+
}
1427+
if (!check_htlc_max_limits(rq, new_flows)) {
1428+
error_message = rq_log(
1429+
rq, rq, LOG_BROKEN,
1430+
"%s: check_htlc_max_limits failed", __func__);
1431+
goto fail;
1432+
}
1433+
13361434
/* no flows should send 0 amount */
13371435
for (size_t i = 0; i < tal_count(new_flows); i++) {
13381436
// FIXME: replace all assertions with LOG_BROKEN

0 commit comments

Comments
 (0)