diff --git a/openingd/openingd.c b/openingd/openingd.c index a0585c6cfd9d..9af7e6c03da0 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -993,6 +993,24 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) return NULL; } + /* BOLT #2: + * + * The sender: + *... + * - MUST set `dust_limit_satoshis` less than or equal to + * `channel_reserve_satoshis` from the `open_channel` message. + */ + if (!state->allowdustreserve && + amount_sat_greater(state->localconf.dust_limit, + state->remoteconf.channel_reserve)) { + negotiation_failed(state, + "Our dust limit %s" + " would be above their reserve %s", + fmt_amount_sat(tmpctx, state->localconf.dust_limit), + fmt_amount_sat(tmpctx, state->remoteconf.channel_reserve)); + return NULL; + } + /* These checks are the same whether we're opener or accepter... */ if (!check_config_bounds(tmpctx, state->funding_sats, state->feerate_per_kw, diff --git a/tests/test_opening.py b/tests/test_opening.py index e23283f7251c..ce391632f65c 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -2266,6 +2266,27 @@ def test_zeroconf_multichan_forward(node_factory): .format(normal_scid, zeroconf_scid)) +def test_dust_limit_above_reserve(node_factory, bitcoind): + """BOLT #2: the accept_channel sender MUST set dust_limit_satoshis + to less than or equal to channel_reserve_satoshis from the + open_channel message (ElementsProject/lightning#9439). + + A stock opener self-bumps its reserve up to its own dust limit, so + the violating open is only reachable when the opener runs + --dev-allowdustreserve and sends its true sub-dust reserve: the + accepter's chainparams dust limit (546) then exceeds it, and the + accepter must fail the channel instead of replying accept_channel. + """ + l1 = node_factory.get_node(options={'dev-allowdustreserve': True}) + l2 = node_factory.get_node() + + l1.fundwallet(10**7) + l1.connect(l2) + + with pytest.raises(RpcError, match='would be above their reserve'): + l1.rpc.fundchannel(l2.info['id'], 10**5, reserve='354sat') + + def test_zeroreserve(node_factory, bitcoind): """Ensure we can set the reserves.