Skip to content

Failure to reject open_channel where funder cannot pay commitment fee #9491

Description

@morehouse

BOLT 2 requires the receiver of open_channel to fail the channel when the funder's amount cannot cover the initial commitment fee:

The receiving node MUST fail the channel if:
  - the funder's amount for the initial commitment transaction is not sufficient for full [fee payment](03-transactions.md#fee-payment).

CLN implements the rule, but too late. The channel isn't rejected until later in the flow, after receiving funding_created.

Impact

A peer can set a push_msat for the channel that leaves insufficient funds to pay the initial commitment fees. CLN initially accepts such channels and responds with accept_channel, even though it will inevitably reject them one roundtrip later in the funding flow (after receiving funding_created). This is entirely a spec compliance issue.

Reproduction

@pytest.mark.openchannel('v1')
def test_open_channel_funder_cannot_afford_fee(node_factory, bitcoind):
    """A funder left short of the commitment fee must be rejected.

    BOLT 2: the receiving node MUST fail the channel if the funder's amount for
    the initial commitment transaction is not sufficient for full fee payment.
    CLN only notices in initial_commit_tx(), after accept_channel has gone out.
    """
    l1 = node_factory.get_node()

    chain_hash = bytes.fromhex(bitcoind.rpc.getblockhash(0))[::-1]
    # Use the node's own opening feerate, so we're inside its accepted range.
    feerate = l1.rpc.feerates('perkw')['perkw']['opening']
    funding_sat = 16777216

    # The funder pays the commitment fee out of its own balance, so pushing the
    # balance away leaves it with nothing to pay from.
    push_msat = funding_sat * 1000

    lconn, channel_type = raw_peer_connect(l1)
    temp_chan_id = os.urandom(32)
    send_open_channel(lconn, chain_hash, temp_chan_id, funding_sat,
                      push_msat, feerate, channel_type)

    mtype = read_channel_reply(lconn)
    assert mtype in (WIRE_WARNING, WIRE_ERROR), \
        "funder left with {} sat to pay the commitment fee was not rejected (got msgtype {})".format(
            funding_sat - push_msat // 1000, mtype)

If we continue to flow to funding_created, the initial_commit_tx check rejects the channel:

UNUSUAL 034f355b...-openingd-chan#1: Funder cannot afford fee on initial commitment transaction

Suggested fix

Apply the same check that already exists in initial_commit_tx immediately after receiving accept_channel.

Discovery

Found while fuzzing the v1 funding protocol with smite.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions