diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index bfacc17e7..dbcfc0423 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -70,6 +70,12 @@ struct config { /* EXPERIMENTAL: offers support */ bool exp_offers; + + /* Allow dust reserves (including 0) when being called via + * `fundchannel` or in the `openchannel` hook. This is a + * slight spec incompatibility, but implementations do this + * already. */ + bool allowdustreserve; }; typedef STRMAP(const char *) alt_subdaemon_map; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index bd0887947..a64764c85 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -946,18 +946,19 @@ bool peer_start_openingd(struct peer *peer, struct peer_fd *peer_fd) msg = towire_openingd_init(NULL, - chainparams, - peer->ld->our_features, - peer->their_features, - &uc->our_config, - max_to_self_delay, - min_effective_htlc_capacity, - &uc->local_basepoints, - &uc->local_funding_pubkey, - uc->minimum_depth, - feerate_min(peer->ld, NULL), - feerate_max(peer->ld, NULL), - IFDEV(peer->ld->dev_force_tmp_channel_id, NULL)); + chainparams, + peer->ld->our_features, + peer->their_features, + &uc->our_config, + max_to_self_delay, + min_effective_htlc_capacity, + &uc->local_basepoints, + &uc->local_funding_pubkey, + uc->minimum_depth, + feerate_min(peer->ld, NULL), + feerate_max(peer->ld, NULL), + IFDEV(peer->ld->dev_force_tmp_channel_id, NULL), + peer->ld->config.allowdustreserve); subd_send_msg(uc->open_daemon, take(msg)); return true; } diff --git a/lightningd/options.c b/lightningd/options.c index ef8f7b008..c40f371d7 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -811,6 +811,8 @@ static const struct config testnet_config = { .connection_timeout_secs = 60, .exp_offers = IFEXPERIMENTAL(true, false), + + .allowdustreserve = false, }; /* aka. "Dude, where's my coins?" */ @@ -875,6 +877,8 @@ static const struct config mainnet_config = { .connection_timeout_secs = 60, .exp_offers = IFEXPERIMENTAL(true, false), + + .allowdustreserve = false, }; static void check_config(struct lightningd *ld) @@ -1168,6 +1172,10 @@ static void register_opts(struct lightningd *ld) &ld->autolisten, "If true, listen on default port and announce if it seems to be a public interface"); + opt_register_arg("--dev-allowdustreserve", opt_set_bool_arg, opt_show_bool, + &ld->config.allowdustreserve, + "If true, we allow the `fundchannel` RPC command and the `openchannel` plugin hook to set a reserve that is below the dust limit."); + opt_register_arg("--proxy", opt_add_proxy_addr, NULL, ld,"Set a socks v5 proxy IP address and port"); opt_register_arg("--tor-service-password", opt_set_talstr, NULL, diff --git a/openingd/openingd.c b/openingd/openingd.c index fa1af8678..40a16a49a 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -101,6 +101,8 @@ struct state { struct feature_set *our_features; struct amount_sat *reserve; + + bool allowdustreserve; }; /*~ If we can't agree on parameters, we fail to open the channel. @@ -960,7 +962,6 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) /* This reserves 1% of the channel (rounded up) */ set_reserve(state, state->remoteconf.dust_limit); -#ifndef ZERORESERVE /* Pending proposal to remove these limits. */ /* BOLT #2: * @@ -982,18 +983,6 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->remoteconf.dust_limit)); return NULL; } - if (amount_sat_greater(state->localconf.dust_limit, - state->remoteconf.channel_reserve)) { - negotiation_failed(state, - "Our dust limit %s" - " would be above their reserve %s", - type_to_string(tmpctx, struct amount_sat, - &state->localconf.dust_limit), - type_to_string(tmpctx, struct amount_sat, - &state->remoteconf.channel_reserve)); - return NULL; - } -#endif /* These checks are the same whether we're opener or accepter... */ if (!check_config_bounds(tmpctx, state->funding_sats, @@ -1434,17 +1423,18 @@ int main(int argc, char *argv[]) /*~ The very first thing we read from lightningd is our init msg */ msg = wire_sync_read(tmpctx, REQ_FD); if (!fromwire_openingd_init(state, msg, - &chainparams, - &state->our_features, - &state->their_features, - &state->localconf, - &state->max_to_self_delay, - &state->min_effective_htlc_capacity, - &state->our_points, - &state->our_funding_pubkey, - &state->minimum_depth, - &state->min_feerate, &state->max_feerate, - &force_tmp_channel_id)) + &chainparams, + &state->our_features, + &state->their_features, + &state->localconf, + &state->max_to_self_delay, + &state->min_effective_htlc_capacity, + &state->our_points, + &state->our_funding_pubkey, + &state->minimum_depth, + &state->min_feerate, &state->max_feerate, + &force_tmp_channel_id, + &state->allowdustreserve)) master_badmsg(WIRE_OPENINGD_INIT, msg); #if DEVELOPER diff --git a/openingd/openingd_wire.csv b/openingd/openingd_wire.csv index 4f77446f2..4ab658773 100644 --- a/openingd/openingd_wire.csv +++ b/openingd/openingd_wire.csv @@ -24,6 +24,10 @@ msgdata,openingd_init,minimum_depth,u32, msgdata,openingd_init,min_feerate,u32, msgdata,openingd_init,max_feerate,u32, msgdata,openingd_init,dev_temporary_channel_id,?byte,32 +# Do we allow `fundchannel` or the `openchannel` hook to set sub-dust +# reserves? This is explicitly required by the spec for safety +# reasons, but some implementations and users keep asking for it. +msgdata,openingd_init,allowdustreserve,bool, # Openingd->master: they offered channel, should we continue? msgtype,openingd_got_offer,6005