diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index b82dfa5d5..addd5f564 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -406,6 +406,8 @@ int main(int argc, const char *argv[]) local_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); remote_config->channel_reserve = AMOUNT_SAT(0); local_config->htlc_minimum = AMOUNT_MSAT(0); diff --git a/common/channel_config.c b/common/channel_config.c index 5b8627c76..c4e991f49 100644 --- a/common/channel_config.c +++ b/common/channel_config.c @@ -9,6 +9,7 @@ void towire_channel_config(u8 **pptr, const struct channel_config *config) towire_amount_msat(pptr, config->htlc_minimum); towire_u16(pptr, config->to_self_delay); 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, @@ -20,4 +21,5 @@ void fromwire_channel_config(const u8 **ptr, size_t *max, config->htlc_minimum = fromwire_amount_msat(ptr, max); config->to_self_delay = fromwire_u16(ptr, max); config->max_accepted_htlcs = fromwire_u16(ptr, max); + config->max_dust_htlc_exposure_msat = fromwire_amount_msat(ptr, max); } diff --git a/common/channel_config.h b/common/channel_config.h index 7078c83dd..fb74a4998 100644 --- a/common/channel_config.h +++ b/common/channel_config.h @@ -71,6 +71,12 @@ struct channel_config { * similarly, `max_accepted_htlcs` limits the number of outstanding * HTLCs the other node can offer. */ 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); diff --git a/devtools/mkcommit.c b/devtools/mkcommit.c index 2c3cdeada..f6afbf32d 100644 --- a/devtools/mkcommit.c +++ b/devtools/mkcommit.c @@ -149,6 +149,7 @@ static int parse_config(char *argv[], config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL); config->htlc_minimum = AMOUNT_MSAT(0); config->max_accepted_htlcs = 483; + config->max_dust_htlc_exposure_msat = AMOUNT_MSAT(-1ULL); config->to_self_delay = atoi(argv[argnum]); argnum++; diff --git a/doc/lightning-listconfigs.7.md b/doc/lightning-listconfigs.7.md index 352bd1c40..52ee273eb 100644 --- a/doc/lightning-listconfigs.7.md +++ b/doc/lightning-listconfigs.7.md @@ -71,6 +71,7 @@ On success, an object is returned, containing: - **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 - **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 - **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) @@ -206,4 +207,4 @@ RESOURCES --------- Main web site: -[comment]: # ( SHA256STAMP:47c067588120e0f9a71206313685cebb2a8c515e9b04b688b202d2772c8f8146) +[comment]: # ( SHA256STAMP:71a911b67203f75e7c1f717be611f505713fce4e8113fc4a84c89bc50730d2bf) diff --git a/doc/schemas/listconfigs.schema.json b/doc/schemas/listconfigs.schema.json index 9f910292f..ca24ba769 100644 --- a/doc/schemas/listconfigs.schema.json +++ b/doc/schemas/listconfigs.schema.json @@ -183,6 +183,10 @@ "type": "u32", "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": { "type": "u64", "description": "`min-capacity-sat` field from config or cmdline, or default" diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 532841dca..553f10a78 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -7,6 +7,8 @@ #include #include +struct amount_msat; + /* Various adjustable things. */ struct config { /* How long do we want them to lock up their funds? (blocks) */ @@ -31,6 +33,9 @@ struct config { /* htlcs per channel */ 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. */ u32 commit_time_ms; diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index 9cd3872e9..d203aed8d 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -132,6 +132,9 @@ void channel_config(struct lightningd *ld, ours->dust_limit = chainparams->dust_limit; 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 */ ours->htlc_minimum = AMOUNT_MSAT(0); diff --git a/lightningd/options.c b/lightningd/options.c index ef65f9dd2..d8431c13c 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -671,6 +672,9 @@ static const struct config testnet_config = { /* Testnet blockspace is free. */ .max_concurrent_htlcs = 483, + /* Max amount of dust allowed per channel (50ksat) */ + .max_dust_htlc_exposure_msat = AMOUNT_MSAT(50000000), + /* Be aggressive on testnet. */ .cltv_expiry_delta = 6, .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 */ .max_concurrent_htlcs = 30, + /* Max amount of dust allowed per channel (50ksat) */ + .max_dust_htlc_exposure_msat = AMOUNT_MSAT(50000000), + /* BOLT #2: * * 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)); } +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) { 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, &ld->config.max_concurrent_htlcs, "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, &ld->config.min_capacity_sat, "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) { /* FIXME: We actually treat it as if they specified * --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 } else if (opt->cb_arg == (void *)opt_set_accept_extra_tlv_types) { /* TODO Actually print the option */ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 022c52e73..e3eb06528 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -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_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++) tx_state->tx_msg_count[i] = 0; diff --git a/openingd/openingd.c b/openingd/openingd.c index 78280f6bc..c8d2cc0d2 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1429,6 +1429,9 @@ int main(int argc, char *argv[]) memset(&state->channel_id, 0, sizeof(state->channel_id)); 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 */ state->upfront_shutdown_script[LOCAL] = state->upfront_shutdown_script[REMOTE] diff --git a/wallet/db.c b/wallet/db.c index 5c884cb16..1b6c8f02d 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -852,6 +852,9 @@ static struct migration dbmigrations[] = { " shared_secret=NULL," " localfailmsg=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. */ diff --git a/wallet/wallet.c b/wallet/wallet.c index d483e1ee7..56180e166 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1711,7 +1711,8 @@ static void wallet_channel_config_save(struct wallet *w, " channel_reserve_satoshis=?," " htlc_minimum_msat=?," " to_self_delay=?," - " max_accepted_htlcs=?" + " max_accepted_htlcs=?," + " max_dust_htlc_exposure_msat=?" " WHERE id=?;")); db_bind_amount_sat(stmt, 0, &cc->dust_limit); 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_int(stmt, 4, cc->to_self_delay); 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)); } @@ -1731,7 +1733,8 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id, const char *query = SQL( "SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, " "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); db_bind_u64(stmt, 0, id); 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); cc->to_self_delay = 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); return ok; }