lightningd: new option for htlc dust limit

To reduce the surface area of amount of a channel balance that can be
eaten up as htlc dust, we introduce a new config
'--max-dust-htlc-exposure-msat', which sets the max amount that any
channel's balance can be added as dust

Changelog-Added: config: new option --max-dust-htlc-exposure-msat, which limits the total amount of sats to be allowed as dust on a channel
This commit is contained in:
niftynei 2021-09-28 14:03:08 -05:00 committed by Christian Decker
parent 0f0a77e322
commit 1fe829c546
13 changed files with 62 additions and 5 deletions

View file

@ -406,6 +406,8 @@ int main(int argc, const char *argv[])
local_config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL); local_config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL);
remote_config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL); remote_config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL);
local_config->max_dust_htlc_exposure_msat = AMOUNT_MSAT(-1ULL);
remote_config->max_dust_htlc_exposure_msat = AMOUNT_MSAT(-1ULL);
local_config->channel_reserve = AMOUNT_SAT(0); local_config->channel_reserve = AMOUNT_SAT(0);
remote_config->channel_reserve = AMOUNT_SAT(0); remote_config->channel_reserve = AMOUNT_SAT(0);
local_config->htlc_minimum = AMOUNT_MSAT(0); local_config->htlc_minimum = AMOUNT_MSAT(0);

View file

@ -9,6 +9,7 @@ void towire_channel_config(u8 **pptr, const struct channel_config *config)
towire_amount_msat(pptr, config->htlc_minimum); towire_amount_msat(pptr, config->htlc_minimum);
towire_u16(pptr, config->to_self_delay); towire_u16(pptr, config->to_self_delay);
towire_u16(pptr, config->max_accepted_htlcs); towire_u16(pptr, config->max_accepted_htlcs);
towire_amount_msat(pptr, config->max_dust_htlc_exposure_msat);
} }
void fromwire_channel_config(const u8 **ptr, size_t *max, void fromwire_channel_config(const u8 **ptr, size_t *max,
@ -20,4 +21,5 @@ void fromwire_channel_config(const u8 **ptr, size_t *max,
config->htlc_minimum = fromwire_amount_msat(ptr, max); config->htlc_minimum = fromwire_amount_msat(ptr, max);
config->to_self_delay = fromwire_u16(ptr, max); config->to_self_delay = fromwire_u16(ptr, max);
config->max_accepted_htlcs = fromwire_u16(ptr, max); config->max_accepted_htlcs = fromwire_u16(ptr, max);
config->max_dust_htlc_exposure_msat = fromwire_amount_msat(ptr, max);
} }

View file

@ -71,6 +71,12 @@ struct channel_config {
* similarly, `max_accepted_htlcs` limits the number of outstanding * similarly, `max_accepted_htlcs` limits the number of outstanding
* HTLCs the other node can offer. */ * HTLCs the other node can offer. */
u16 max_accepted_htlcs; u16 max_accepted_htlcs;
/* BOLT-TBD #X
*
* maximum dust exposure allowed for this channel
*/
struct amount_msat max_dust_htlc_exposure_msat;
}; };
void towire_channel_config(u8 **pptr, const struct channel_config *config); void towire_channel_config(u8 **pptr, const struct channel_config *config);

View file

@ -149,6 +149,7 @@ static int parse_config(char *argv[],
config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL); config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL);
config->htlc_minimum = AMOUNT_MSAT(0); config->htlc_minimum = AMOUNT_MSAT(0);
config->max_accepted_htlcs = 483; config->max_accepted_htlcs = 483;
config->max_dust_htlc_exposure_msat = AMOUNT_MSAT(-1ULL);
config->to_self_delay = atoi(argv[argnum]); config->to_self_delay = atoi(argv[argnum]);
argnum++; argnum++;

View file

@ -71,6 +71,7 @@ On success, an object is returned, containing:
- **rescan** (integer, optional): `rescan` field from config or cmdline, or default - **rescan** (integer, optional): `rescan` field from config or cmdline, or default
- **fee-per-satoshi** (u32, optional): `fee-per-satoshi` field from config or cmdline, or default - **fee-per-satoshi** (u32, optional): `fee-per-satoshi` field from config or cmdline, or default
- **max-concurrent-htlcs** (u32, optional): `max-concurrent-htlcs` field from config or cmdline, or default - **max-concurrent-htlcs** (u32, optional): `max-concurrent-htlcs` field from config or cmdline, or default
- **max-dust-htlc-exposure-msat** (msat, optional): `max-dust-htlc-exposure-mast` field from config or cmdline, or default
- **min-capacity-sat** (u64, optional): `min-capacity-sat` field from config or cmdline, or default - **min-capacity-sat** (u64, optional): `min-capacity-sat` field from config or cmdline, or default
- **addr** (string, optional): `addr` field from config or cmdline (can be more than one) - **addr** (string, optional): `addr` field from config or cmdline (can be more than one)
- **announce-addr** (string, optional): `announce-addr` field from config or cmdline (can be more than one) - **announce-addr** (string, optional): `announce-addr` field from config or cmdline (can be more than one)
@ -206,4 +207,4 @@ RESOURCES
--------- ---------
Main web site: <https://github.com/ElementsProject/lightning> Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:47c067588120e0f9a71206313685cebb2a8c515e9b04b688b202d2772c8f8146) [comment]: # ( SHA256STAMP:71a911b67203f75e7c1f717be611f505713fce4e8113fc4a84c89bc50730d2bf)

View file

@ -183,6 +183,10 @@
"type": "u32", "type": "u32",
"description": "`max-concurrent-htlcs` field from config or cmdline, or default" "description": "`max-concurrent-htlcs` field from config or cmdline, or default"
}, },
"max-dust-htlc-exposure-msat": {
"type": "msat",
"description": "`max-dust-htlc-exposure-mast` field from config or cmdline, or default"
},
"min-capacity-sat": { "min-capacity-sat": {
"type": "u64", "type": "u64",
"description": "`min-capacity-sat` field from config or cmdline, or default" "description": "`min-capacity-sat` field from config or cmdline, or default"

View file

@ -7,6 +7,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
struct amount_msat;
/* Various adjustable things. */ /* Various adjustable things. */
struct config { struct config {
/* How long do we want them to lock up their funds? (blocks) */ /* How long do we want them to lock up their funds? (blocks) */
@ -31,6 +33,9 @@ struct config {
/* htlcs per channel */ /* htlcs per channel */
u32 max_concurrent_htlcs; u32 max_concurrent_htlcs;
/* Max amount of dust allowed per channel */
struct amount_msat max_dust_htlc_exposure_msat;
/* How long between changing commit and sending COMMIT message. */ /* How long between changing commit and sending COMMIT message. */
u32 commit_time_ms; u32 commit_time_ms;

View file

@ -132,6 +132,9 @@ void channel_config(struct lightningd *ld,
ours->dust_limit = chainparams->dust_limit; ours->dust_limit = chainparams->dust_limit;
ours->max_htlc_value_in_flight = AMOUNT_MSAT(UINT64_MAX); ours->max_htlc_value_in_flight = AMOUNT_MSAT(UINT64_MAX);
ours->max_dust_htlc_exposure_msat
= ld->config.max_dust_htlc_exposure_msat;
/* Don't care */ /* Don't care */
ours->htlc_minimum = AMOUNT_MSAT(0); ours->htlc_minimum = AMOUNT_MSAT(0);

View file

@ -10,6 +10,7 @@
#include <common/features.h> #include <common/features.h>
#include <common/hsm_encryption.h> #include <common/hsm_encryption.h>
#include <common/json_command.h> #include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/json_tok.h> #include <common/json_tok.h>
#include <common/param.h> #include <common/param.h>
#include <common/type_to_string.h> #include <common/type_to_string.h>
@ -671,6 +672,9 @@ static const struct config testnet_config = {
/* Testnet blockspace is free. */ /* Testnet blockspace is free. */
.max_concurrent_htlcs = 483, .max_concurrent_htlcs = 483,
/* Max amount of dust allowed per channel (50ksat) */
.max_dust_htlc_exposure_msat = AMOUNT_MSAT(50000000),
/* Be aggressive on testnet. */ /* Be aggressive on testnet. */
.cltv_expiry_delta = 6, .cltv_expiry_delta = 6,
.cltv_final = 10, .cltv_final = 10,
@ -717,6 +721,9 @@ static const struct config mainnet_config = {
/* While up to 483 htlcs are possible we do 30 by default (as eclair does) to save blockspace */ /* While up to 483 htlcs are possible we do 30 by default (as eclair does) to save blockspace */
.max_concurrent_htlcs = 30, .max_concurrent_htlcs = 30,
/* Max amount of dust allowed per channel (50ksat) */
.max_dust_htlc_exposure_msat = AMOUNT_MSAT(50000000),
/* BOLT #2: /* BOLT #2:
* *
* 1. the `cltv_expiry_delta` for channels, `3R+2G+2S`: if in doubt, a * 1. the `cltv_expiry_delta` for channels, `3R+2G+2S`: if in doubt, a
@ -842,6 +849,14 @@ static char *opt_start_daemon(struct lightningd *ld)
errx(1, "Died with signal %u", WTERMSIG(exitcode)); errx(1, "Died with signal %u", WTERMSIG(exitcode));
} }
static char *opt_set_msat(const char *arg, struct amount_msat *amt)
{
if (!parse_amount_msat(amt, arg, strlen(arg)))
return tal_fmt(NULL, "Unable to parse millisatoshi '%s'", arg);
return NULL;
}
static char *opt_set_wumbo(struct lightningd *ld) static char *opt_set_wumbo(struct lightningd *ld)
{ {
feature_set_or(ld->our_features, feature_set_or(ld->our_features,
@ -1005,6 +1020,9 @@ static void register_opts(struct lightningd *ld)
opt_register_arg("--max-concurrent-htlcs", opt_set_u32, opt_show_u32, opt_register_arg("--max-concurrent-htlcs", opt_set_u32, opt_show_u32,
&ld->config.max_concurrent_htlcs, &ld->config.max_concurrent_htlcs,
"Number of HTLCs one channel can handle concurrently. Should be between 1 and 483"); "Number of HTLCs one channel can handle concurrently. Should be between 1 and 483");
opt_register_arg("--max-dust-htlc-exposure-msat", opt_set_msat,
NULL, &ld->config.max_dust_htlc_exposure_msat,
"Max HTLC amount that can be trimmed");
opt_register_arg("--min-capacity-sat", opt_set_u64, opt_show_u64, opt_register_arg("--min-capacity-sat", opt_set_u64, opt_show_u64,
&ld->config.min_capacity_sat, &ld->config.min_capacity_sat,
"Minimum capacity in satoshis for accepting channels"); "Minimum capacity in satoshis for accepting channels");
@ -1496,6 +1514,8 @@ static void add_config(struct lightningd *ld,
|| opt->cb_arg == (void *)plugin_opt_flag_set) { || opt->cb_arg == (void *)plugin_opt_flag_set) {
/* FIXME: We actually treat it as if they specified /* FIXME: We actually treat it as if they specified
* --plugin for each one, so ignore these */ * --plugin for each one, so ignore these */
} else if (opt->cb_arg == (void *)opt_set_msat) {
json_add_amount_msat_only(response, name0, ld->config.max_dust_htlc_exposure_msat);
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
} else if (opt->cb_arg == (void *)opt_set_accept_extra_tlv_types) { } else if (opt->cb_arg == (void *)opt_set_accept_extra_tlv_types) {
/* TODO Actually print the option */ /* TODO Actually print the option */

View file

@ -134,6 +134,9 @@ static struct tx_state *new_tx_state(const tal_t *ctx)
tx_state->lease_chan_max_msat = 0; tx_state->lease_chan_max_msat = 0;
tx_state->lease_chan_max_ppt = 0; tx_state->lease_chan_max_ppt = 0;
/* no max_htlc_dust_exposure on remoteconf, we exclusively use the local's */
tx_state->remoteconf.max_dust_htlc_exposure_msat = AMOUNT_MSAT(0);
for (size_t i = 0; i < NUM_TX_MSGS; i++) for (size_t i = 0; i < NUM_TX_MSGS; i++)
tx_state->tx_msg_count[i] = 0; tx_state->tx_msg_count[i] = 0;

View file

@ -1429,6 +1429,9 @@ int main(int argc, char *argv[])
memset(&state->channel_id, 0, sizeof(state->channel_id)); memset(&state->channel_id, 0, sizeof(state->channel_id));
state->channel = NULL; state->channel = NULL;
/* Default this to zero, we only ever look at the local */
state->remoteconf.max_dust_htlc_exposure_msat = AMOUNT_MSAT(0);
/*~ We set these to NULL, meaning no requirements on shutdown */ /*~ We set these to NULL, meaning no requirements on shutdown */
state->upfront_shutdown_script[LOCAL] state->upfront_shutdown_script[LOCAL]
= state->upfront_shutdown_script[REMOTE] = state->upfront_shutdown_script[REMOTE]

View file

@ -852,6 +852,9 @@ static struct migration dbmigrations[] = {
" shared_secret=NULL," " shared_secret=NULL,"
" localfailmsg=NULL" " localfailmsg=NULL"
" WHERE (hstate=9 OR hstate=19);"), NULL}, " WHERE (hstate=9 OR hstate=19);"), NULL},
/* We default to 50k sats */
{SQL("ALTER TABLE channel_configs ADD max_dust_htlc_exposure_msat BIGINT DEFAULT 50000000"), NULL},
{SQL("ALTER TABLE channel_htlcs ADD fail_immediate INTEGER DEFAULT 0"), NULL},
}; };
/* Leak tracking. */ /* Leak tracking. */

View file

@ -1711,7 +1711,8 @@ static void wallet_channel_config_save(struct wallet *w,
" channel_reserve_satoshis=?," " channel_reserve_satoshis=?,"
" htlc_minimum_msat=?," " htlc_minimum_msat=?,"
" to_self_delay=?," " to_self_delay=?,"
" max_accepted_htlcs=?" " max_accepted_htlcs=?,"
" max_dust_htlc_exposure_msat=?"
" WHERE id=?;")); " WHERE id=?;"));
db_bind_amount_sat(stmt, 0, &cc->dust_limit); db_bind_amount_sat(stmt, 0, &cc->dust_limit);
db_bind_amount_msat(stmt, 1, &cc->max_htlc_value_in_flight); db_bind_amount_msat(stmt, 1, &cc->max_htlc_value_in_flight);
@ -1719,7 +1720,8 @@ static void wallet_channel_config_save(struct wallet *w,
db_bind_amount_msat(stmt, 3, &cc->htlc_minimum); db_bind_amount_msat(stmt, 3, &cc->htlc_minimum);
db_bind_int(stmt, 4, cc->to_self_delay); db_bind_int(stmt, 4, cc->to_self_delay);
db_bind_int(stmt, 5, cc->max_accepted_htlcs); db_bind_int(stmt, 5, cc->max_accepted_htlcs);
db_bind_u64(stmt, 6, cc->id); db_bind_amount_msat(stmt, 6, &cc->max_dust_htlc_exposure_msat);
db_bind_u64(stmt, 7, cc->id);
db_exec_prepared_v2(take(stmt)); db_exec_prepared_v2(take(stmt));
} }
@ -1731,7 +1733,8 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id,
const char *query = SQL( const char *query = SQL(
"SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, " "SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, "
"channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, " "channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, "
"max_accepted_htlcs FROM channel_configs WHERE id= ? ;"); "max_accepted_htlcs, max_dust_htlc_exposure_msat"
" FROM channel_configs WHERE id= ? ;");
struct db_stmt *stmt = db_prepare_v2(w->db, query); struct db_stmt *stmt = db_prepare_v2(w->db, query);
db_bind_u64(stmt, 0, id); db_bind_u64(stmt, 0, id);
db_query_prepared(stmt); db_query_prepared(stmt);
@ -1746,7 +1749,8 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id,
db_column_amount_msat(stmt, col++, &cc->htlc_minimum); db_column_amount_msat(stmt, col++, &cc->htlc_minimum);
cc->to_self_delay = db_column_int(stmt, col++); cc->to_self_delay = db_column_int(stmt, col++);
cc->max_accepted_htlcs = db_column_int(stmt, col++); cc->max_accepted_htlcs = db_column_int(stmt, col++);
assert(col == 7); db_column_amount_msat(stmt, col++, &cc->max_dust_htlc_exposure_msat);
assert(col == 8);
tal_free(stmt); tal_free(stmt);
return ok; return ok;
} }