Skip to content

Commit 719f875

Browse files
committed
dusty-htlcs: enforce limit on dusty htlcs
for every new added htlc, check that adding it won't go over our 'dust budget' (which assumes a slightly higher than current feerate, as this prevents sudden feerate changes from overshooting our dust budget) note that if the feerate changes surpass the limits we've set, we immediately fail the channel.
1 parent 121594f commit 719f875

8 files changed

+182
-1
lines changed

channeld/channeld.c

+12
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,14 @@ static void send_commit(struct peer *peer)
12931293
if (feerate_changes_done(peer->channel->fee_states, false)) {
12941294
u8 *msg;
12951295

1296+
/* Is this feerate update going to push the committed
1297+
* htlcs over our allowed dust limits? */
1298+
if (!htlc_dust_ok(peer->channel, feerate_target, REMOTE)
1299+
|| !htlc_dust_ok(peer->channel, feerate_target, LOCAL))
1300+
/* We fail the channel. Oops */
1301+
peer_failed_err(peer->pps, &peer->channel_id,
1302+
"Too much dust to update fee");
1303+
12961304
if (!channel_update_feerate(peer->channel, feerate_target))
12971305
status_failed(STATUS_FAIL_INTERNAL_ERROR,
12981306
"Could not afford feerate %u"
@@ -3260,6 +3268,10 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
32603268
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
32613269
failstr = "Too many HTLCs";
32623270
goto failed;
3271+
case CHANNEL_ERR_DUST_FAILURE:
3272+
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
3273+
failstr = "HTLC too dusty, allowed dust limit reached";
3274+
goto failed;
32633275
}
32643276
/* Shouldn't return anything else! */
32653277
abort();

channeld/commit_tx.c

+16
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ size_t commit_tx_num_untrimmed(const struct htlc **htlcs,
3535
return n;
3636
}
3737

38+
bool commit_tx_amount_trimmed(const struct htlc **htlcs,
39+
u32 feerate_per_kw,
40+
struct amount_sat dust_limit,
41+
bool option_anchor_outputs,
42+
enum side side,
43+
struct amount_msat *amt)
44+
{
45+
for (size_t i = 0; i < tal_count(htlcs); i++) {
46+
if (trim(htlcs[i], feerate_per_kw, dust_limit,
47+
option_anchor_outputs, side))
48+
if (!amount_msat_add(amt, *amt, htlcs[i]->amount))
49+
return false;
50+
}
51+
return true;
52+
}
53+
3854
static void add_offered_htlc_out(struct bitcoin_tx *tx, size_t n,
3955
const struct htlc *htlc,
4056
const struct keyset *keyset,

channeld/commit_tx.h

+20
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ size_t commit_tx_num_untrimmed(const struct htlc **htlcs,
2424
bool option_anchor_outputs,
2525
enum side side);
2626

27+
/**
28+
* commit_tx_amount_trimmed: what's the sum of trimmed htlc amounts?
29+
* @htlcs: tal_arr of HTLCs
30+
* @feerate_per_kw: feerate to use
31+
* @dust_limit: dust limit below which to trim outputs.
32+
* @option_anchor_outputs: does option_anchor_outputs apply to this channel?
33+
* @side: from which side's point of view
34+
* @amt: returned, total value trimmed from this commitment
35+
*
36+
* We need @side because HTLC fees are different for offered and
37+
* received HTLCs.
38+
*
39+
* Returns false if unable to calculate amount trimmed.
40+
*/
41+
bool commit_tx_amount_trimmed(const struct htlc **htlcs,
42+
u32 feerate_per_kw,
43+
struct amount_sat dust_limit,
44+
bool option_anchor_outputs,
45+
enum side side,
46+
struct amount_msat *amt);
2747
/**
2848
* commit_tx: create (unsigned) commitment tx to spend the funding tx output
2949
* @ctx: context to allocate transaction and @htlc_map from.

channeld/full_channel.c

+105-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <common/blockheight_states.h>
88
#include <common/features.h>
99
#include <common/fee_states.h>
10+
#include <common/htlc_trim.h>
1011
#include <common/htlc_tx.h>
1112
#include <common/htlc_wire.h>
1213
#include <common/keyset.h>
@@ -426,6 +427,37 @@ static struct amount_sat fee_for_htlcs(const struct channel *channel,
426427
return commit_tx_base_fee(feerate, untrimmed, option_anchor_outputs);
427428
}
428429

430+
static bool htlc_dust(const struct channel *channel,
431+
const struct htlc **committed,
432+
const struct htlc **adding,
433+
const struct htlc **removing,
434+
enum side side,
435+
u32 feerate,
436+
struct amount_msat *trim_total)
437+
{
438+
struct amount_sat dust_limit = channel->config[side].dust_limit;
439+
bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS);
440+
struct amount_msat trim_rmvd = AMOUNT_MSAT(0);
441+
442+
if (!commit_tx_amount_trimmed(committed, feerate,
443+
dust_limit,
444+
option_anchor_outputs,
445+
side, trim_total))
446+
return false;
447+
if (!commit_tx_amount_trimmed(adding, feerate,
448+
dust_limit,
449+
option_anchor_outputs,
450+
side, trim_total))
451+
return false;
452+
if (!commit_tx_amount_trimmed(removing, feerate,
453+
dust_limit,
454+
option_anchor_outputs,
455+
side, &trim_rmvd))
456+
return false;
457+
458+
return amount_msat_sub(trim_total, *trim_total, trim_rmvd);
459+
}
460+
429461
/*
430462
* There is a corner case where the opener can spend so much that the
431463
* non-opener can't add any non-dust HTLCs (since the opener would
@@ -500,12 +532,14 @@ static enum channel_add_err add_htlc(struct channel *channel,
500532
bool err_immediate_failures)
501533
{
502534
struct htlc *htlc, *old;
503-
struct amount_msat msat_in_htlcs, committed_msat, adding_msat, removing_msat;
535+
struct amount_msat msat_in_htlcs, committed_msat,
536+
adding_msat, removing_msat, htlc_dust_amt;
504537
enum side sender = htlc_state_owner(state), recipient = !sender;
505538
const struct htlc **committed, **adding, **removing;
506539
const struct channel_view *view;
507540
size_t htlc_count;
508541
bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS);
542+
u32 feerate, feerate_ceil;
509543

510544
htlc = tal(tmpctx, struct htlc);
511545

@@ -756,6 +790,42 @@ static enum channel_add_err add_htlc(struct channel *channel,
756790
}
757791
}
758792

793+
htlc_dust_amt = AMOUNT_MSAT(0);
794+
feerate = channel_feerate(channel, recipient);
795+
/* Note that we check for trimmed htlcs at an
796+
* *accelerated* rate, so that future feerate changes
797+
* don't suddenly surprise us */
798+
feerate_ceil = htlc_trim_feerate_ceiling(feerate);
799+
800+
if (!htlc_dust(channel, committed,
801+
adding, removing, recipient,
802+
feerate_ceil, &htlc_dust_amt))
803+
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
804+
805+
if (amount_msat_greater(htlc_dust_amt,
806+
channel->config[LOCAL].max_dust_htlc_exposure_msat)) {
807+
htlc->fail_immediate = true;
808+
if (err_immediate_failures)
809+
return CHANNEL_ERR_DUST_FAILURE;
810+
}
811+
812+
813+
/* Also check the sender, as they'll eventually have the same
814+
* constraint */
815+
htlc_dust_amt = AMOUNT_MSAT(0);
816+
feerate = channel_feerate(channel, sender);
817+
feerate_ceil = htlc_trim_feerate_ceiling(feerate);
818+
if (!htlc_dust(channel, committed, adding,
819+
removing, sender, feerate_ceil,
820+
&htlc_dust_amt))
821+
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
822+
823+
if (amount_msat_greater(htlc_dust_amt,
824+
channel->config[LOCAL].max_dust_htlc_exposure_msat)) {
825+
htlc->fail_immediate = true;
826+
if (err_immediate_failures)
827+
return CHANNEL_ERR_DUST_FAILURE;
828+
}
759829
dump_htlc(htlc, "NEW:");
760830
htlc_map_add(channel->htlcs, tal_steal(channel, htlc));
761831
if (htlcp)
@@ -1112,6 +1182,37 @@ u32 approx_max_feerate(const struct channel *channel)
11121182
return avail.satoshis / weight * 1000; /* Raw: once-off reverse feerate*/
11131183
}
11141184

1185+
/* Is the sum of trimmed htlcs, as this new feerate, above our
1186+
* max allowed htlc dust limit? */
1187+
static struct amount_msat htlc_calculate_dust(const struct channel *channel,
1188+
u32 feerate_per_kw,
1189+
enum side side)
1190+
{
1191+
const struct htlc **committed, **adding, **removing;
1192+
struct amount_msat acc_dust = AMOUNT_MSAT(0);
1193+
1194+
gather_htlcs(tmpctx, channel, side,
1195+
&committed, &removing, &adding);
1196+
1197+
htlc_dust(channel, committed, adding, removing,
1198+
side, feerate_per_kw, &acc_dust);
1199+
1200+
return acc_dust;
1201+
}
1202+
1203+
bool htlc_dust_ok(const struct channel *channel,
1204+
u32 feerate_per_kw,
1205+
enum side side)
1206+
{
1207+
struct amount_msat total_dusted;
1208+
1209+
total_dusted = htlc_calculate_dust(channel, feerate_per_kw, side);
1210+
1211+
return amount_msat_greater_eq(
1212+
channel->config[LOCAL].max_dust_htlc_exposure_msat,
1213+
total_dusted);
1214+
}
1215+
11151216
bool can_opener_afford_feerate(const struct channel *channel, u32 feerate_per_kw)
11161217
{
11171218
struct amount_sat needed, fee;
@@ -1183,6 +1284,9 @@ bool channel_update_feerate(struct channel *channel, u32 feerate_per_kw)
11831284
if (!can_opener_afford_feerate(channel, feerate_per_kw))
11841285
return false;
11851286

1287+
if (!htlc_dust_ok(channel, feerate_per_kw, REMOTE))
1288+
return false;
1289+
11861290
status_debug("Setting %s feerate to %u",
11871291
side_to_str(!channel->opener), feerate_per_kw);
11881292

channeld/full_channel.h

+12
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,18 @@ u32 approx_max_feerate(const struct channel *channel);
182182
*/
183183
bool can_opener_afford_feerate(const struct channel *channel, u32 feerate);
184184

185+
/**
186+
* htlc_dust_ok: will this feerate keep our dusted htlc's beneath
187+
* the updated feerate?
188+
*
189+
* @channel: The channel state
190+
* @feerate_per_kw: new feerate to test ok'ness for
191+
* @side: which side's htlcs to verify
192+
*/
193+
bool htlc_dust_ok(const struct channel *channel,
194+
u32 feerate_per_kw,
195+
enum side side);
196+
185197
/**
186198
* channel_update_feerate: Change fee rate on non-opener side.
187199
* @channel: The channel

channeld/full_channel_error.h

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ enum channel_add_err {
2020
CHANNEL_ERR_HTLC_BELOW_MINIMUM,
2121
/* HTLC would push past max_accepted_htlcs */
2222
CHANNEL_ERR_TOO_MANY_HTLCS,
23+
/* HTLC would push dusted-htlcs above max_dust_htlc_exposure_msat */
24+
CHANNEL_ERR_DUST_FAILURE,
2325
};
2426

2527
enum channel_remove_err {

common/htlc_trim.c

+12
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,15 @@ bool htlc_is_trimmed(enum side htlc_owner,
4242
return true;
4343
return amount_msat_less_sat(htlc_amount, htlc_min);
4444
}
45+
46+
/* Minimum amount of headroom we should use for
47+
* anticipated feerate adjustments */
48+
#define HTLC_FEE_MIN_RANGE 2530
49+
#define max(a, b) ((a) > (b) ? (a) : (b))
50+
51+
u32 htlc_trim_feerate_ceiling(u32 feerate_per_kw)
52+
{
53+
/* Add the greater of 1.25x or 2530 sat/kw */
54+
return max(feerate_per_kw + feerate_per_kw / 4,
55+
feerate_per_kw + HTLC_FEE_MIN_RANGE);
56+
}

common/htlc_trim.h

+3
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ bool htlc_is_trimmed(enum side htlc_owner,
1212
enum side side,
1313
bool option_anchor_outputs);
1414

15+
/* Calculate the our htlc-trimming buffer feerate
16+
* (max(25%, 10s/vbyte) above feerate_per_kw) */
17+
u32 htlc_trim_feerate_ceiling(u32 feerate_per_kw);
1518
#endif /* LIGHTNING_COMMON_HTLC_TRIM_H */

0 commit comments

Comments
 (0)