Skip to content

Commit b193eb0

Browse files
niftyneicdecker
authored andcommitted
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 42e40c1 commit b193eb0

File tree

8 files changed

+182
-1
lines changed

8 files changed

+182
-1
lines changed

channeld/channeld.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,14 @@ static void send_commit(struct peer *peer)
12921292
if (feerate_changes_done(peer->channel->fee_states, false)) {
12931293
u8 *msg;
12941294

1295+
/* Is this feerate update going to push the committed
1296+
* htlcs over our allowed dust limits? */
1297+
if (!htlc_dust_ok(peer->channel, feerate_target, REMOTE)
1298+
|| !htlc_dust_ok(peer->channel, feerate_target, LOCAL))
1299+
/* We fail the channel. Oops */
1300+
peer_failed_err(peer->pps, &peer->channel_id,
1301+
"Too much dust to update fee");
1302+
12951303
if (!channel_update_feerate(peer->channel, feerate_target))
12961304
status_failed(STATUS_FAIL_INTERNAL_ERROR,
12971305
"Could not afford feerate %u"
@@ -3360,6 +3368,10 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
33603368
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
33613369
failstr = "Too many HTLCs";
33623370
goto failed;
3371+
case CHANNEL_ERR_DUST_FAILURE:
3372+
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
3373+
failstr = "HTLC too dusty, allowed dust limit reached";
3374+
goto failed;
33633375
}
33643376
/* Shouldn't return anything else! */
33653377
abort();

channeld/commit_tx.c

Lines changed: 16 additions & 0 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 105 additions & 1 deletion
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>
@@ -423,6 +424,37 @@ static struct amount_sat fee_for_htlcs(const struct channel *channel,
423424
return commit_tx_base_fee(feerate, untrimmed, option_anchor_outputs);
424425
}
425426

427+
static bool htlc_dust(const struct channel *channel,
428+
const struct htlc **committed,
429+
const struct htlc **adding,
430+
const struct htlc **removing,
431+
enum side side,
432+
u32 feerate,
433+
struct amount_msat *trim_total)
434+
{
435+
struct amount_sat dust_limit = channel->config[side].dust_limit;
436+
bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS);
437+
struct amount_msat trim_rmvd = AMOUNT_MSAT(0);
438+
439+
if (!commit_tx_amount_trimmed(committed, feerate,
440+
dust_limit,
441+
option_anchor_outputs,
442+
side, trim_total))
443+
return false;
444+
if (!commit_tx_amount_trimmed(adding, feerate,
445+
dust_limit,
446+
option_anchor_outputs,
447+
side, trim_total))
448+
return false;
449+
if (!commit_tx_amount_trimmed(removing, feerate,
450+
dust_limit,
451+
option_anchor_outputs,
452+
side, &trim_rmvd))
453+
return false;
454+
455+
return amount_msat_sub(trim_total, *trim_total, trim_rmvd);
456+
}
457+
426458
/*
427459
* There is a corner case where the opener can spend so much that the
428460
* non-opener can't add any non-dust HTLCs (since the opener would
@@ -497,12 +529,14 @@ static enum channel_add_err add_htlc(struct channel *channel,
497529
bool err_immediate_failures)
498530
{
499531
struct htlc *htlc, *old;
500-
struct amount_msat msat_in_htlcs, committed_msat, adding_msat, removing_msat;
532+
struct amount_msat msat_in_htlcs, committed_msat,
533+
adding_msat, removing_msat, htlc_dust_amt;
501534
enum side sender = htlc_state_owner(state), recipient = !sender;
502535
const struct htlc **committed, **adding, **removing;
503536
const struct channel_view *view;
504537
size_t htlc_count;
505538
bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS);
539+
u32 feerate, feerate_ceil;
506540

507541
htlc = tal(tmpctx, struct htlc);
508542

@@ -753,6 +787,42 @@ static enum channel_add_err add_htlc(struct channel *channel,
753787
}
754788
}
755789

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

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

1284+
if (!htlc_dust_ok(channel, feerate_per_kw, REMOTE))
1285+
return false;
1286+
11831287
status_debug("Setting %s feerate to %u",
11841288
side_to_str(!channel->opener), feerate_per_kw);
11851289

channeld/full_channel.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,18 @@ u32 approx_max_feerate(const struct channel *channel);
180180
*/
181181
bool can_opener_afford_feerate(const struct channel *channel, u32 feerate);
182182

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

channeld/full_channel_error.h

Lines changed: 2 additions & 0 deletions
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

Lines changed: 12 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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)