diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index aaa3e8fb8bc7..d8490de9ab74 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -415,9 +415,23 @@ RPC call lightning-setchannel(7). * **htlc-maximum-msat**=*MILLISATOSHI* - Default: unset (no limit). Sets the maximum allowed HTLC value for newly created -channels. If you want to change the `htlc_maximum_msat` for existing channels, -use the RPC call lightning-setchannel(7). + Sets the maximum allowed HTLC value for newly created channels. If unset +(the default), public channels advertise 25% of the channel capacity: a +maximum well below the publicly-known capacity makes it harder to probe for +where payments are flowing. Private channels, whose capacity is not public, +advertise the full amount they can send. Either way this is capped at what we +can actually send, and an explicit value here overrides the default (up to +that cap). It is also raised to `htlc_minimum_msat` where that is higher, +since the spec requires the maximum to be at least the minimum. If you want +to change the `htlc_maximum_msat` for existing +channels, use the RPC call lightning-setchannel(7), for example: + + lightning-cli listpeerchannels | \ + jq -r '.channels[] | select(.private == false and .short_channel_id) | + "\(.short_channel_id) \((.total_msat // 0) / 4 | floor)"' | \ + while read scid max; do + lightning-cli setchannel "$scid" htlcmax="${max}msat" + done * **announce-addr-discovered**=*BOOL* diff --git a/lightningd/channel.c b/lightningd/channel.c index 692d81980150..698c972fcf09 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -489,6 +489,57 @@ struct amount_msat htlc_max_possible_send(const struct channel *channel) return lower_bound_msat; } +struct amount_msat channel_htlc_maximum_default(const struct channel *channel, + struct amount_msat configured_max) +{ + struct amount_msat cap = htlc_max_possible_send(channel); + struct amount_msat deflt; + + /* If the operator set --htlc-maximum-msat, honour it (the sentinel + * AMOUNT_MSAT(-1ULL) means "unset"). Otherwise pick a default. */ + if (!amount_msat_eq(configured_max, AMOUNT_MSAT(-1ULL))) + deflt = configured_max; + else if (channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL) { + /* Oakland privacy proposal (Lightning Dev Summit): probing for + * where payments went is much harder if the htlc maximum is + * well below the channel capacity. For public channels the + * capacity is known from the funding output, so default to 25% + * of it. */ + if (!amount_sat_to_msat(&deflt, channel->funding_sats)) + deflt = cap; + else + deflt = amount_msat_div(deflt, 4); + } else + /* Private channels have no publicly-known capacity to correlate + * against, so we advertise the full amount we can send. */ + deflt = cap; + + /* BOLT #7: + * + * - MUST set `htlc_maximum_msat` to the maximum value it will send through this channel for a single HTLC. + * - MUST set this to less than or equal to the channel capacity. + * - MUST set this to less than or equal to `max_htlc_value_in_flight_msat` it received from the peer. + * - MUST set this to greater than or equal to `htlc_minimum_msat`. + */ + /* A quarter of the capacity can land below a high htlc_minimum_msat: + * a routable channel beats the stronger privacy margin. */ + if (amount_msat_less(deflt, channel->htlc_minimum_msat)) + deflt = channel->htlc_minimum_msat; + + /* htlc_max_possible_send() covers both upper bounds above. If it is + * itself below htlc_minimum_msat then no value satisfies the spec, so + * say so rather than advertising an unroutable channel silently. */ + if (amount_msat_less(cap, channel->htlc_minimum_msat)) + log_unusual(channel->log, + "htlc_minimum_msat %s exceeds the most we can send" + " (%s): channel_update will not be routable", + fmt_amount_msat(tmpctx, channel->htlc_minimum_msat), + fmt_amount_msat(tmpctx, cap)); + + /* Never advertise more than we could actually send. */ + return amount_msat_min(deflt, cap); +} + struct channel *new_channel(struct peer *peer, u64 dbid, /* NULL or stolen */ struct wallet_shachain *their_shachain, @@ -567,7 +618,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, bool withheld) { struct channel *channel = tal(peer->ld, struct channel); - struct amount_msat htlc_min, htlc_max; + struct amount_msat htlc_min; bool anysegwit = !chainparams->is_elements && feature_negotiated(peer->ld->our_features, peer->their_features, @@ -694,11 +745,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->htlc_minimum_msat = htlc_min; else channel->htlc_minimum_msat = htlc_minimum_msat; - htlc_max = htlc_max_possible_send(channel); - if (amount_msat_less(htlc_max, htlc_maximum_msat)) - channel->htlc_maximum_msat = htlc_max; - else - channel->htlc_maximum_msat = htlc_maximum_msat; + channel->htlc_maximum_msat = channel_htlc_maximum_default(channel, + htlc_maximum_msat); list_add_tail(&peer->channels, &channel->list); channel->rr_number = peer->ld->rr_counter++; @@ -1350,4 +1398,3 @@ const u8 *channel_update_for_error(const tal_t *ctx, return channel_gossip_update_for_error(ctx, channel); } - diff --git a/lightningd/channel.h b/lightningd/channel.h index 8e3a499ad09c..bfc7302d08c5 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -977,6 +977,15 @@ const u8 *channel_update_for_error(const tal_t *ctx, struct amount_msat htlc_max_possible_send(const struct channel *channel); +/* Default htlc_maximum_msat to advertise for a new channel, given the + * configured --htlc-maximum-msat (AMOUNT_MSAT(-1ULL) if unset). Public + * channels default to 25% of capacity for privacy; private channels and an + * explicit setting use the full amount, all capped at what we can send and + * floored at channel->htlc_minimum_msat (which must therefore already be + * set). */ +struct amount_msat channel_htlc_maximum_default(const struct channel *channel, + struct amount_msat configured_max); + /* Given features, what channel_type do we want? */ struct channel_type *desired_channel_type(const tal_t *ctx, const struct feature_set *our_features, diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 7c440e59098b..cf3c0b81c81d 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1255,7 +1255,8 @@ wallet_update_channel(struct lightningd *ld, channel->msat_to_us_max = our_msat; channel->lease_expiry = lease_expiry; channel->htlc_minimum_msat = channel->channel_info.their_config.htlc_minimum; - channel->htlc_maximum_msat = htlc_max_possible_send(channel); + channel->htlc_maximum_msat = channel_htlc_maximum_default(channel, + ld->config.htlc_maximum_msat); tal_free(channel->lease_commit_sig); channel->lease_commit_sig = tal_steal(channel, lease_commit_sig); @@ -1486,7 +1487,8 @@ wallet_commit_channel(struct lightningd *ld, channel->lease_chan_max_msat = lease_chan_max_msat; channel->lease_chan_max_ppt = lease_chan_max_ppt; channel->htlc_minimum_msat = channel_info->their_config.htlc_minimum; - channel->htlc_maximum_msat = htlc_max_possible_send(channel); + channel->htlc_maximum_msat = channel_htlc_maximum_default(channel, + ld->config.htlc_maximum_msat); /* Filled in when we have PSBT for inflight */ channel->funding_psbt = NULL; diff --git a/tests/test_pay.py b/tests/test_pay.py index fdf09cda03f9..2b7035f302d5 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -2069,8 +2069,8 @@ def test_setchannel_usage(node_factory, bitcoind): DEF_BASE = 10 DEF_BASE_MSAT = Millisatoshi(DEF_BASE) DEF_PPM = 100 - # Minus reserve - MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.99)) + # Public channels default htlc_maximum_msat to 25% of capacity. + MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.25)) l1, l2, l3 = node_factory.get_nodes(3, opts={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) @@ -2089,7 +2089,7 @@ def channel_get_config(scid): db_fees = l1.db_query('SELECT feerate_base, feerate_ppm, htlc_maximum_msat FROM channels;') assert(db_fees[0]['feerate_base'] == DEF_BASE) assert(db_fees[0]['feerate_ppm'] == DEF_PPM) - # This will be the capacity - reserves: + # This will be 25% of the capacity: assert(db_fees[0]['htlc_maximum_msat'] == MAX_HTLC) # this is also what listpeers should return channel = only_one(l1.rpc.listpeerchannels()['channels']) @@ -2306,7 +2306,8 @@ def test_setchannel_routing(node_factory, bitcoind): # - htlc max is honored DEF_BASE = 1 DEF_PPM = 10 - MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.99)) + # Public channels default htlc_maximum_msat to 25% of capacity. + MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.25)) MIN_HTLC = Millisatoshi(0) l1, l2, l3 = node_factory.line_graph( @@ -2418,6 +2419,8 @@ def test_setchannel_zero(node_factory, bitcoind): # - payment can be done using zero fees DEF_BASE = 1 DEF_PPM = 10 + # This is the cap (capacity minus reserve) that setchannel clamps to, + # not the default: below we try to set htlcmax above it. MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.99)) l1, l2, l3 = node_factory.line_graph( @@ -2469,7 +2472,8 @@ def test_setchannel_restart(node_factory, bitcoind): DEF_BASE = 1 DEF_PPM = 10 MIN_HTLC = Millisatoshi(0) - MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.99)) + # Public channels default htlc_maximum_msat to 25% of capacity. + MAX_HTLC = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.25)) OPTS = {'may_reconnect': True, 'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM} l1, l2, l3 = node_factory.line_graph(3, announce_channels=True, wait_for_announce=True, opts=OPTS) @@ -2580,6 +2584,41 @@ def test_setchannel_startup_opts(node_factory, bitcoind): assert result[1]['htlc_maximum_msat'] == Millisatoshi(5) +def test_htlc_maximum_msat_default(node_factory, bitcoind): + """Public channels default htlc_maximum_msat to 25% of capacity, private + channels to everything we can send""" + # A public channel's capacity is known from the funding output, so we + # advertise well below it to make probing harder. + PUBLIC_MAX = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.25)) + l1, l2 = node_factory.line_graph(2, wait_for_announce=True) + + scid = only_one(l1.rpc.listpeerchannels()['channels'])['short_channel_id'] + assert only_one(l1.rpc.listpeerchannels()['channels'])['maximum_htlc_out_msat'] == PUBLIC_MAX + # Both directions default the same way. + wait_for(lambda: [c['htlc_maximum_msat'] for c in l1.rpc.listchannels(scid)['channels']] == [PUBLIC_MAX, PUBLIC_MAX]) + + # A private channel has no publicly-known capacity to correlate against, + # so we advertise everything we can send: capacity minus their reserve. + PRIVATE_MAX = Millisatoshi(int(FUNDAMOUNT * 1000 * 0.99)) + l3, l4 = node_factory.line_graph(2, announce_channels=False) + + assert only_one(l3.rpc.listpeerchannels()['channels'])['maximum_htlc_out_msat'] == PRIVATE_MAX + assert only_one(l4.rpc.listpeerchannels()['channels'])['maximum_htlc_out_msat'] == PRIVATE_MAX + + +def test_htlc_maximum_msat_not_below_minimum(node_factory, bitcoind): + """BOLT #7 requires htlc_maximum_msat >= htlc_minimum_msat, so the 25% + public default must not undercut a higher htlc-minimum-msat""" + # 25% of capacity is 250000000msat, so this minimum sits above the default. + HTLC_MIN = Millisatoshi(300000000) + l1, l2 = node_factory.line_graph(2, opts={'htlc-minimum-msat': HTLC_MIN}) + + for n in (l1, l2): + chan = only_one(n.rpc.listpeerchannels()['channels']) + assert chan['minimum_htlc_out_msat'] == HTLC_MIN + assert chan['maximum_htlc_out_msat'] >= chan['minimum_htlc_out_msat'] + + @pytest.mark.parametrize("anchors", [False, True]) def test_channel_spendable(node_factory, bitcoind, anchors): """Test that spendable_msat is accurate"""