diff --git a/channeld/channeld.c b/channeld/channeld.c index 5eb0fb26c..0de935bf0 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1292,6 +1292,14 @@ static void send_commit(struct peer *peer) if (feerate_changes_done(peer->channel->fee_states, false)) { u8 *msg; + /* Is this feerate update going to push the committed + * htlcs over our allowed dust limits? */ + if (!htlc_dust_ok(peer->channel, feerate_target, REMOTE) + || !htlc_dust_ok(peer->channel, feerate_target, LOCAL)) + /* We fail the channel. Oops */ + peer_failed_err(peer->pps, &peer->channel_id, + "Too much dust to update fee"); + if (!channel_update_feerate(peer->channel, feerate_target)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could not afford feerate %u" @@ -3360,6 +3368,10 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer)); failstr = "Too many HTLCs"; goto failed; + case CHANNEL_ERR_DUST_FAILURE: + failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer)); + failstr = "HTLC too dusty, allowed dust limit reached"; + goto failed; } /* Shouldn't return anything else! */ abort(); diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 3eec18440..9c2f7499f 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -35,6 +35,22 @@ size_t commit_tx_num_untrimmed(const struct htlc **htlcs, return n; } +bool commit_tx_amount_trimmed(const struct htlc **htlcs, + u32 feerate_per_kw, + struct amount_sat dust_limit, + bool option_anchor_outputs, + enum side side, + struct amount_msat *amt) +{ + for (size_t i = 0; i < tal_count(htlcs); i++) { + if (trim(htlcs[i], feerate_per_kw, dust_limit, + option_anchor_outputs, side)) + if (!amount_msat_add(amt, *amt, htlcs[i]->amount)) + return false; + } + return true; +} + static void add_offered_htlc_out(struct bitcoin_tx *tx, size_t n, const struct htlc *htlc, const struct keyset *keyset, diff --git a/channeld/commit_tx.h b/channeld/commit_tx.h index 1de552ef6..fc2db029d 100644 --- a/channeld/commit_tx.h +++ b/channeld/commit_tx.h @@ -24,6 +24,26 @@ size_t commit_tx_num_untrimmed(const struct htlc **htlcs, bool option_anchor_outputs, enum side side); +/** + * commit_tx_amount_trimmed: what's the sum of trimmed htlc amounts? + * @htlcs: tal_arr of HTLCs + * @feerate_per_kw: feerate to use + * @dust_limit: dust limit below which to trim outputs. + * @option_anchor_outputs: does option_anchor_outputs apply to this channel? + * @side: from which side's point of view + * @amt: returned, total value trimmed from this commitment + * + * We need @side because HTLC fees are different for offered and + * received HTLCs. + * + * Returns false if unable to calculate amount trimmed. + */ +bool commit_tx_amount_trimmed(const struct htlc **htlcs, + u32 feerate_per_kw, + struct amount_sat dust_limit, + bool option_anchor_outputs, + enum side side, + struct amount_msat *amt); /** * commit_tx: create (unsigned) commitment tx to spend the funding tx output * @ctx: context to allocate transaction and @htlc_map from. diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 59eb23acd..4fb9fc59b 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -423,6 +424,37 @@ static struct amount_sat fee_for_htlcs(const struct channel *channel, return commit_tx_base_fee(feerate, untrimmed, option_anchor_outputs); } +static bool htlc_dust(const struct channel *channel, + const struct htlc **committed, + const struct htlc **adding, + const struct htlc **removing, + enum side side, + u32 feerate, + struct amount_msat *trim_total) +{ + struct amount_sat dust_limit = channel->config[side].dust_limit; + bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS); + struct amount_msat trim_rmvd = AMOUNT_MSAT(0); + + if (!commit_tx_amount_trimmed(committed, feerate, + dust_limit, + option_anchor_outputs, + side, trim_total)) + return false; + if (!commit_tx_amount_trimmed(adding, feerate, + dust_limit, + option_anchor_outputs, + side, trim_total)) + return false; + if (!commit_tx_amount_trimmed(removing, feerate, + dust_limit, + option_anchor_outputs, + side, &trim_rmvd)) + return false; + + return amount_msat_sub(trim_total, *trim_total, trim_rmvd); +} + /* * There is a corner case where the opener can spend so much that the * 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, bool err_immediate_failures) { struct htlc *htlc, *old; - struct amount_msat msat_in_htlcs, committed_msat, adding_msat, removing_msat; + struct amount_msat msat_in_htlcs, committed_msat, + adding_msat, removing_msat, htlc_dust_amt; enum side sender = htlc_state_owner(state), recipient = !sender; const struct htlc **committed, **adding, **removing; const struct channel_view *view; size_t htlc_count; bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS); + u32 feerate, feerate_ceil; htlc = tal(tmpctx, struct htlc); @@ -753,6 +787,42 @@ static enum channel_add_err add_htlc(struct channel *channel, } } + htlc_dust_amt = AMOUNT_MSAT(0); + feerate = channel_feerate(channel, recipient); + /* Note that we check for trimmed htlcs at an + * *accelerated* rate, so that future feerate changes + * don't suddenly surprise us */ + feerate_ceil = htlc_trim_feerate_ceiling(feerate); + + if (!htlc_dust(channel, committed, + adding, removing, recipient, + feerate_ceil, &htlc_dust_amt)) + return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED; + + if (amount_msat_greater(htlc_dust_amt, + channel->config[LOCAL].max_dust_htlc_exposure_msat)) { + htlc->fail_immediate = true; + if (err_immediate_failures) + return CHANNEL_ERR_DUST_FAILURE; + } + + + /* Also check the sender, as they'll eventually have the same + * constraint */ + htlc_dust_amt = AMOUNT_MSAT(0); + feerate = channel_feerate(channel, sender); + feerate_ceil = htlc_trim_feerate_ceiling(feerate); + if (!htlc_dust(channel, committed, adding, + removing, sender, feerate_ceil, + &htlc_dust_amt)) + return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED; + + if (amount_msat_greater(htlc_dust_amt, + channel->config[LOCAL].max_dust_htlc_exposure_msat)) { + htlc->fail_immediate = true; + if (err_immediate_failures) + return CHANNEL_ERR_DUST_FAILURE; + } dump_htlc(htlc, "NEW:"); htlc_map_add(channel->htlcs, tal_steal(channel, htlc)); if (htlcp) @@ -1109,6 +1179,37 @@ u32 approx_max_feerate(const struct channel *channel) return avail.satoshis / weight * 1000; /* Raw: once-off reverse feerate*/ } +/* Is the sum of trimmed htlcs, as this new feerate, above our + * max allowed htlc dust limit? */ +static struct amount_msat htlc_calculate_dust(const struct channel *channel, + u32 feerate_per_kw, + enum side side) +{ + const struct htlc **committed, **adding, **removing; + struct amount_msat acc_dust = AMOUNT_MSAT(0); + + gather_htlcs(tmpctx, channel, side, + &committed, &removing, &adding); + + htlc_dust(channel, committed, adding, removing, + side, feerate_per_kw, &acc_dust); + + return acc_dust; +} + +bool htlc_dust_ok(const struct channel *channel, + u32 feerate_per_kw, + enum side side) +{ + struct amount_msat total_dusted; + + total_dusted = htlc_calculate_dust(channel, feerate_per_kw, side); + + return amount_msat_greater_eq( + channel->config[LOCAL].max_dust_htlc_exposure_msat, + total_dusted); +} + bool can_opener_afford_feerate(const struct channel *channel, u32 feerate_per_kw) { struct amount_sat needed, fee; @@ -1180,6 +1281,9 @@ bool channel_update_feerate(struct channel *channel, u32 feerate_per_kw) if (!can_opener_afford_feerate(channel, feerate_per_kw)) return false; + if (!htlc_dust_ok(channel, feerate_per_kw, REMOTE)) + return false; + status_debug("Setting %s feerate to %u", side_to_str(!channel->opener), feerate_per_kw); diff --git a/channeld/full_channel.h b/channeld/full_channel.h index ebfb4f856..6f674a75f 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -180,6 +180,18 @@ u32 approx_max_feerate(const struct channel *channel); */ bool can_opener_afford_feerate(const struct channel *channel, u32 feerate); +/** + * htlc_dust_ok: will this feerate keep our dusted htlc's beneath + * the updated feerate? + * + * @channel: The channel state + * @feerate_per_kw: new feerate to test ok'ness for + * @side: which side's htlcs to verify + */ +bool htlc_dust_ok(const struct channel *channel, + u32 feerate_per_kw, + enum side side); + /** * channel_update_feerate: Change fee rate on non-opener side. * @channel: The channel diff --git a/channeld/full_channel_error.h b/channeld/full_channel_error.h index 49ca03a39..05deffb86 100644 --- a/channeld/full_channel_error.h +++ b/channeld/full_channel_error.h @@ -20,6 +20,8 @@ enum channel_add_err { CHANNEL_ERR_HTLC_BELOW_MINIMUM, /* HTLC would push past max_accepted_htlcs */ CHANNEL_ERR_TOO_MANY_HTLCS, + /* HTLC would push dusted-htlcs above max_dust_htlc_exposure_msat */ + CHANNEL_ERR_DUST_FAILURE, }; enum channel_remove_err { diff --git a/common/htlc_trim.c b/common/htlc_trim.c index acd2f8374..e47c5fdb0 100644 --- a/common/htlc_trim.c +++ b/common/htlc_trim.c @@ -42,3 +42,15 @@ bool htlc_is_trimmed(enum side htlc_owner, return true; return amount_msat_less_sat(htlc_amount, htlc_min); } + +/* Minimum amount of headroom we should use for + * anticipated feerate adjustments */ +#define HTLC_FEE_MIN_RANGE 2530 +#define max(a, b) ((a) > (b) ? (a) : (b)) + +u32 htlc_trim_feerate_ceiling(u32 feerate_per_kw) +{ + /* Add the greater of 1.25x or 2530 sat/kw */ + return max(feerate_per_kw + feerate_per_kw / 4, + feerate_per_kw + HTLC_FEE_MIN_RANGE); +} diff --git a/common/htlc_trim.h b/common/htlc_trim.h index 113834cfd..0044de45c 100644 --- a/common/htlc_trim.h +++ b/common/htlc_trim.h @@ -12,4 +12,7 @@ bool htlc_is_trimmed(enum side htlc_owner, enum side side, bool option_anchor_outputs); +/* Calculate the our htlc-trimming buffer feerate + * (max(25%, 10s/vbyte) above feerate_per_kw) */ +u32 htlc_trim_feerate_ceiling(u32 feerate_per_kw); #endif /* LIGHTNING_COMMON_HTLC_TRIM_H */