From 4f946a6f14a05ee9a2fee3a9b61a315bc09b31c5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 18 Jul 2023 06:59:29 +0930 Subject: [PATCH 01/12] BOLT 2, 3, 9: option_simple_close. Pay your own fees, so the peer will sign without caring. Even if it doesn't relay. Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 93 ++++++++++++++++++++++++++++++++++++++++++++- 03-transactions.md | 44 ++++++++++++++++++++- 09-features.md | 2 + 3 files changed, 137 insertions(+), 2 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 27b01fe04..353ad7472 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -36,6 +36,7 @@ operation, and closing. * [Channel Close](#channel-close) * [Closing Initiation: `shutdown`](#closing-initiation-shutdown) * [Closing Negotiation: `closing_signed`](#closing-negotiation-closing_signed) + * [Closing Negotiation: `closing_complete` and `closing_sig`](#closing-negotiation-closing_complete-and-closing_sig) * [Normal Operation](#normal-operation) * [Forwarding HTLCs](#forwarding-htlcs) * [`cltv_expiry_delta` Selection](#cltv_expiry_delta-selection) @@ -1521,10 +1522,24 @@ Closing happens in two stages: | |<-(?)-- closing_signed Fn----| | +-------+ +-------+ + +-------+ +-------+ + | |--(1)----- shutdown ------->| | + | |<-(2)----- shutdown --------| | + | | | | + | | | | + | A | ... | B | + | | | | + | |--(3a)- closing_complete Fee->| | + | |<-(3b)- closing_complete Fee--| | + | |<-(4a)- closing_sig ----------| | + | |--(4b)- closing_sig --------->| | + +-------+ +-------+ + ### Closing Initiation: `shutdown` Either node (or both) can send a `shutdown` message to initiate closing, -along with the `scriptpubkey` it wants to be paid to. +along with the `scriptpubkey` it wants to be paid to. This can be +sent multiple times. 1. type: 38 (`shutdown`) 2. data: @@ -1713,6 +1728,82 @@ satoshis, which is possible if `dust_limit_satoshis` is below 546 satoshis). No funds are at risk when that happens, but the channel must be force-closed as the closing transaction will likely never reach miners. +### Closing Negotiation: `closing_complete` and `closing_sig` + +Once shutdown is complete, the channel is empty of HTLCs, there are no commitments +for which a revocation is owed, and all updates are included on both commitments, +the final current commitment transactions will have no HTLCs. + +Each peer says what fee it will pay, and the other side simply signs that transaction. The only complexity comes from allowing each side to omit its own output should it be uneconomic. + +This process will be repeated every time a `shutdown` message is received, which allows re-negotiation. + +1. type: 40 (`closing_complete`) +2. data: + * [`channel_id`:`channel_id`] + * [`u64`:`fee_satoshis`] + * [`u8`: `has_closer_output`] + * [`signature`:`signature_with_closee_output`] + * [`signature`:`signature_without_closee_output`] + +1. type: 41 (`closing_sig`) +2. data: + * [`channel_id`:`channel_id`] + * [`u8`: `has_closee_output`] + * [`signature`:`signature`] + +#### Requirements + +Note: the details and requirements for the transaction being signed are in [BOLT 3](03-transactions.md#closing-transaction)). + +Both nodes: + - After a `shutdown` has been received, AND no HTLCs remain in either commitment transaction: + - SHOULD send a `closing_complete` message. + +The sender of `closing_complete` (aka. "the closer"): + - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. + - SHOULD set `has_closer_output` to 0 if it considers its own remaining balance to be uneconomic. + - Otherwise MUST set `has_closer_output` to 1. + - If it sets `has_closer_output` to 1: + - MUST set `signature_with_closee_output` to a valid signature of a transaction with both closer and closee outputs. + - MUST set `signature_without_closee_output` to a valid signature of a transaction with only a closer output. + - Otherwise: (`has_closer_output` is 0): + - MUST set `signature_with_closee_output` to a valid signature of a transaction with only the closee output. + - MUST set `signature_without_closee_output` to a valid signature of a transaction with only the null output as described in [BOLT 3](03-transactions.md#closing-transaction). + +The receiver of `closing_complete` (aka. "the closee"): + - if either `signature_with_closee_output` or `signature_without_closee_output` is not valid for the closing transactions specified in [BOLT #3](03-transactions.md#closing-transaction) OR non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. + - Otherwise: + - MUST select one of the signatures (and thus, transactions) to respond to. + - MUST sign and broadcast that transaction. + - MUST send `closing_sig`. + +The sender of `closing_sig`: + - if it selected `signature_with_closee_output` to broadcast: + - MUST set `has_closee_output` to 1. + - MUST set `signature` to a valid signature on that transaction. + - otherwise (it selected `signature_without_closee_output`): + - MUST set `has_closee_output` to 0. + - MUST set `signature` to a valid signature on that transaction. + +The receiver of `closing_sig`: + - MUST broadcast the transaction indicated by `has_closee_output`. + +### Rationale + +The close protocol is designed to avoid any failure scenarios caused by fee disagreement, since each side offers to pay its own desired fee. + +Multiple signatures are given, so each side can choose whether it wants to include its own output. In the case of large fees and tiny channels, where neither side wants its output, the use of an OP_RETURN simply cleans up the dangling unspent transaction output. This is expected to be extremely rare. + +Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. + +If the closer proposes a transaction which will not relay (either its own output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. + +Similarly, if the closer proposes a high fee, it doesn't harm the closee to sign the transaction, as the closer is paying. + +There's a slight game where each side would prefer the other side pay the fee, and proposes a minimal fee. If neither side proposes a fee which will relay, the negotiation can occur again, or the final commitment transaction can be spent. In practice, the opener has an incentive to offer a reasonable closing fee, as they would pay the fee for the commitment transaction, which also costs more to spend. + ## Normal Operation Once both nodes have exchanged `channel_ready` (and optionally [`announcement_signatures`](07-routing-gossip.md#the-announcement_signatures-message)), the channel can be used to make payments via Hashed Time Locked Contracts. diff --git a/03-transactions.md b/03-transactions.md index 0fcdf5cdb..c1bb72be4 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -349,7 +349,9 @@ The witness script for the output is: To spend this via penalty, the remote node uses a witness stack ` 1`, and to collect the output, the local node uses an input with nSequence `to_self_delay` and a witness stack ` 0`. -## Closing Transaction +## Classic Closing Transaction + +This variant is used for `closing_signed` messages (i.e. where `option_simple_close` is not negotiated). Note that there are two possible variants for each node. @@ -390,6 +392,46 @@ has been used. There will be at least one output, if the funding amount is greater than twice `dust_limit_satoshis`. +## Closing Transaction + +This variant is used for `closing_complete` and `closing_sig` messages (i.e. where `option_simple_close` is negotiated). + +In this case, the node sending `closing_complete` ("the closer") pays the fees, and the sequence is set to 0xFFFFFFFD to allow RBF. The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). + +Two closing transactions are always produced: one `with_closee_output` one `without_closee_output` (the non-closer chooses which to accept). `closing_complete` contains `has_closer_output` to indicate whether the closer's output is in the transactions. + +* version: 2 +* locktime: 0 +* txin count: 1 + * `txin[0]` outpoint: `txid` and `output_index` from `funding_created` message + * `txin[0]` sequence: 0xFFFFFFFD + * `txin[0]` script bytes: 0 + * `txin[0]` witness: `0 ` + +* txout count: 1 or 2 of the following + * The closer output: + * `txout` amount: the final balance for the closer, minus `closing_complete` `fee_satoshis`, rounded down to whole satoshis. + * `txout` script: as specified in that closer's `scriptpubkey` in its `shutdown` message + * The closee output: + * `txout` amount: the final balance for the closer, rounded down to whole satoshis. + * `txout` script: as specified in that closee's `scriptpubkey` in its `shutdown` message + * The null output: + * `txout` amount: 0 + * `txout` script: `feeeee` `OP_RETURN` (102 101 101 101 101 101 106). + +### Requirements + +Each node offering a signature: + - MUST round each output down to whole satoshis. + - MUST subtract the fee given by `fee_satoshis` from the closer output. + + +### Rationale + +The case where both sides omit their outputs due to a de-minimus channel is never expected to happen, however it is +documented here for completeness, and serves to avoid an polluting the unspent outputs. Unfortunately, the transaction +has to be at least 65 bytes to propagate, so the `OP_RETURN` includes padding. + ## Fees ### Fee Calculation diff --git a/09-features.md b/09-features.md index 45be48465..e498f1a54 100644 --- a/09-features.md +++ b/09-features.md @@ -51,6 +51,7 @@ The Context column decodes as follows: | 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | | 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) | | 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | +| 60/61 | `option_simple_close` | Simplified closing negotiation | IN | `option_shutdown_anysegwit` | [BOLT #2][bolt02-simple-close] | ## Requirements @@ -96,6 +97,7 @@ This work is licensed under a [Creative Commons Attribution 4.0 International Li [bolt02-retransmit]: 02-peer-protocol.md#message-retransmission [bolt02-open]: 02-peer-protocol.md#the-open_channel-message +[bolt02-simple-close]: 02-peer-protocol.md#closing-negotiation-closing_complete-and-closing_sig [bolt03-htlc-tx]: 03-transactions.md#htlc-timeout-and-htlc-success-transactions [bolt02-shutdown]: 02-peer-protocol.md#closing-initiation-shutdown [bolt02-quiescence]: 02-peer-protocol.md#channel-quiescence From ee0c6f64596e10b62587af14d26d79b8a8c38413 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 18 Jul 2023 06:59:33 +0930 Subject: [PATCH 02/12] BOLT 2: fix battling requirements for `shutdown` The shutdown section says: ``` - MUST NOT send multiple `shutdown` messages. ``` But the reconnection section says: ``` - upon reconnection: - if it has sent a previous `shutdown`: - MUST retransmit `shutdown`. ``` So clearly, remove the former. Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 1 - 1 file changed, 1 deletion(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 353ad7472..324ddd970 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1555,7 +1555,6 @@ A sending node: - MAY send a `shutdown` before a `channel_ready`, i.e. before the funding transaction has reached `minimum_depth`. - if there are updates pending on the receiving node's commitment transaction: - MUST NOT send a `shutdown`. - - MUST NOT send multiple `shutdown` messages. - MUST NOT send an `update_add_htlc` after a `shutdown`. - if no HTLCs remain in either commitment transaction (including dust HTLCs) and neither side has a pending `revoke_and_ack` to send: From a5388ab3eea49ef92e7596fd634b806fa3cbf02d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 1 Aug 2023 05:36:21 +0930 Subject: [PATCH 03/12] Require non-dust output for closer. You have to give them something which will propagate. Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 324ddd970..e64ccd0ec 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1761,6 +1761,7 @@ Both nodes: The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. + - MUST set `has_closee_output` to 0 if it would be dust (< 540 satoshis for P2SH, < 330 satoshis for P2WSH and P2TR) - SHOULD set `has_closer_output` to 0 if it considers its own remaining balance to be uneconomic. - Otherwise MUST set `has_closer_output` to 1. - If it sets `has_closer_output` to 1: @@ -1771,6 +1772,8 @@ The sender of `closing_complete` (aka. "the closer"): - MUST set `signature_without_closee_output` to a valid signature of a transaction with only the null output as described in [BOLT 3](03-transactions.md#closing-transaction). The receiver of `closing_complete` (aka. "the closee"): + - If `has_closee_output` is 1 and the closer's output would be dust (< 540 satoshis for P2SH, < 330 satoshis for P2WSH and P2TR): + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - if either `signature_with_closee_output` or `signature_without_closee_output` is not valid for the closing transactions specified in [BOLT #3](03-transactions.md#closing-transaction) OR non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - Otherwise: From 1a00338e8997dc02a24343512306ea9aeed59dd4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 13 Sep 2023 14:30:39 +0930 Subject: [PATCH 04/12] BOLT 2: Rewrite to use TLV, and only allow the lesser-amount to drop output. If both are dust, you should lowball fees. The next patch adds OP_RETURN as a valid shutdown scriptpubkey though if you really want to do this. This also addresses the case where people send a new `shutdown` with a *different* scriptpubkey. This could previously cause a race where you receive a bad signature (because it hasn't received the updated shutdown), so we ignore these cases. Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 98 ++++++++++++++++++++++++++++++--------------- 03-transactions.md | 9 ++--- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index e64ccd0ec..d7c018aae 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1733,74 +1733,106 @@ Once shutdown is complete, the channel is empty of HTLCs, there are no commitmen for which a revocation is owed, and all updates are included on both commitments, the final current commitment transactions will have no HTLCs. -Each peer says what fee it will pay, and the other side simply signs that transaction. The only complexity comes from allowing each side to omit its own output should it be uneconomic. +Each peer says what fee it will pay, and the other side simply signs that transaction. The lesser-paid peer (if either is) can opt to omit their own output from the closing tx. -This process will be repeated every time a `shutdown` message is received, which allows re-negotiation. +This process will be repeated every time a `shutdown` message is received, which allows re-negotiation (and RBF). 1. type: 40 (`closing_complete`) 2. data: * [`channel_id`:`channel_id`] * [`u64`:`fee_satoshis`] - * [`u8`: `has_closer_output`] - * [`signature`:`signature_with_closee_output`] - * [`signature`:`signature_without_closee_output`] + * [`closing_tlvs`:`tlvs`] + +1. `tlv_stream`: `closing_tlvs` +2. types: + 1. type: 1 (`closer_no_closee`) + 2. data: + * [`signature`:`sig`] + 1. type: 2 (`no_closer_closee`) + 2. data: + * [`signature`:`sig`] + 1. type: 3 (`closer_and_closee`) + 2. data: + * [`signature`:`sig`] 1. type: 41 (`closing_sig`) 2. data: * [`channel_id`:`channel_id`] - * [`u8`: `has_closee_output`] - * [`signature`:`signature`] + * [`closing_tlvs`:`tlvs`] #### Requirements Note: the details and requirements for the transaction being signed are in [BOLT 3](03-transactions.md#closing-transaction)). +An output is *dust* if: +- It is P2SH and the amount is < 540 satoshis +- It is P2WSH or P2TR and the amount is < 330 satoshis + Both nodes: - After a `shutdown` has been received, AND no HTLCs remain in either commitment transaction: - SHOULD send a `closing_complete` message. The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. - - MUST set `has_closee_output` to 0 if it would be dust (< 540 satoshis for P2SH, < 330 satoshis for P2WSH and P2TR) - - SHOULD set `has_closer_output` to 0 if it considers its own remaining balance to be uneconomic. - - Otherwise MUST set `has_closer_output` to 1. - - If it sets `has_closer_output` to 1: - - MUST set `signature_with_closee_output` to a valid signature of a transaction with both closer and closee outputs. - - MUST set `signature_without_closee_output` to a valid signature of a transaction with only a closer output. - - Otherwise: (`has_closer_output` is 0): - - MUST set `signature_with_closee_output` to a valid signature of a transaction with only the closee output. - - MUST set `signature_without_closee_output` to a valid signature of a transaction with only the null output as described in [BOLT 3](03-transactions.md#closing-transaction). + - MUST set `fee_satoshis` so that at least one output is not dust. + - MUST use the last send and received `shutdown` `scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). + - If it sets `signature` fields, MUST set them as valid signature using its `funding_pubkey` of: + - `closer_noclosee`: closing transaction with only the local ("closer") output. + - `no_closer_closee`: closing transaction with only the remote ("closee") output. + - `closer_and_closee`: closing transaction with both the closer and closee outputs. + - If the local outstanding balance (in millisatoshi) is less than the remote outstanding balance: + - MUST NOT set `closer_no_closee`. + - MUST set exactly one of `no_closer_closee` or `closer_and_closee`. + - MUST set `no_closer_closee` if the local output amount is dust. + - MAY set `no_closer_closee` if it considers the closee output amount uneconomic. + - Otherwise (not lesser amount, cannot remove own output): + - MUST NOT set `no_closer_closee`. + - MUST set both `closer_no_closee` and `closer_and_closee`. The receiver of `closing_complete` (aka. "the closee"): - - If `has_closee_output` is 1 and the closer's output would be dust (< 540 satoshis for P2SH, < 330 satoshis for P2WSH and P2TR): + - If `fee_satoshis` is greater than the closer's outstanding balance: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - - if either `signature_with_closee_output` or `signature_without_closee_output` is not valid for the closing transactions specified in [BOLT #3](03-transactions.md#closing-transaction) OR non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): + - Select a signature for validation: + - if the local output amount is dust: + - MUST use `closer_no_closee`. + - otherwise, if it considers the closee output amount uneconomic: + - MUST use `closer_no_closee`. + - otherwise, if `closer_and_closee` is present: + - MUST use `closer_and_closee`. + - otherwise: + - MUST use `no_closer_closee`. + - If the selected signature field does not exist: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - - Otherwise: - - MUST select one of the signatures (and thus, transactions) to respond to. - - MUST sign and broadcast that transaction. - - MUST send `closing_sig`. - -The sender of `closing_sig`: - - if it selected `signature_with_closee_output` to broadcast: - - MUST set `has_closee_output` to 1. - - MUST set `signature` to a valid signature on that transaction. - - otherwise (it selected `signature_without_closee_output`): - - MUST set `has_closee_output` to 0. - - MUST set `signature` to a valid signature on that transaction. + - If the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): + - MUST ignore `closing_complete`. + - If the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. + - MUST sign and broadcast the corresponding closing transaction. + - MUST send `closing_sig` with a single valid signature in the same tlv field as the `closing_complete`. The receiver of `closing_sig`: - - MUST broadcast the transaction indicated by `has_closee_output`. + - if `tlvs` does not contain exactly one signature: + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. + - if `tlvs` does not contain one of the tlv fields sent in `closing_complete`: + - MUST ignore `closing_complete`. + - if the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): + - MUST ignore `closing_complete`. + - of the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. + - otherwise: + - MUST sign and broadcast the corrsponding closing transaction. ### Rationale The close protocol is designed to avoid any failure scenarios caused by fee disagreement, since each side offers to pay its own desired fee. -Multiple signatures are given, so each side can choose whether it wants to include its own output. In the case of large fees and tiny channels, where neither side wants its output, the use of an OP_RETURN simply cleans up the dangling unspent transaction output. This is expected to be extremely rare. +If one side has less funds than the other, it may choose to omit its own output, and in this case dust MUST be omitted, to ensure the resulting transaction can be broadcast. Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. -If the closer proposes a transaction which will not relay (either its own output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. +However, sending a new `shutdown` message overrides previous ones, so you can negotiated again (even changing the output address) if you want: in this case there's a race where you could receive a `closing_complete` for the previous output address, and the signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad signatures are simply ignored. + +If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. Similarly, if the closer proposes a high fee, it doesn't harm the closee to sign the transaction, as the closer is paying. diff --git a/03-transactions.md b/03-transactions.md index c1bb72be4..2e312c295 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -398,7 +398,7 @@ This variant is used for `closing_complete` and `closing_sig` messages (i.e. whe In this case, the node sending `closing_complete` ("the closer") pays the fees, and the sequence is set to 0xFFFFFFFD to allow RBF. The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). -Two closing transactions are always produced: one `with_closee_output` one `without_closee_output` (the non-closer chooses which to accept). `closing_complete` contains `has_closer_output` to indicate whether the closer's output is in the transactions. +The side with lesser funds can opt to omit their own output. * version: 2 * locktime: 0 @@ -408,16 +408,13 @@ Two closing transactions are always produced: one `with_closee_output` one `with * `txin[0]` script bytes: 0 * `txin[0]` witness: `0 ` -* txout count: 1 or 2 of the following +* txout count: 1 or 2 * The closer output: * `txout` amount: the final balance for the closer, minus `closing_complete` `fee_satoshis`, rounded down to whole satoshis. * `txout` script: as specified in that closer's `scriptpubkey` in its `shutdown` message * The closee output: - * `txout` amount: the final balance for the closer, rounded down to whole satoshis. + * `txout` amount: the final balance for the closee, rounded down to whole satoshis. * `txout` script: as specified in that closee's `scriptpubkey` in its `shutdown` message - * The null output: - * `txout` amount: 0 - * `txout` script: `feeeee` `OP_RETURN` (102 101 101 101 101 101 106). ### Requirements From 05272948f32c6bb71281d40b3de7ab5a5765cce1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 25 Sep 2023 11:03:29 +0930 Subject: [PATCH 05/12] BOLT 2: allow standard OP_RETURN as an output type. This gets around "but both our outputs are dust!" problems, as recommended by Anthony Towns. I hope I interpreted the standardness rules correctly (technically, you can have multiple pushes in an OP_RETURN as long as the total is under 83 bytes, but let's keep it simple). Add an explicit note that "OP_RETURN" is never considered "uneconomic". Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index d7c018aae..54629d047 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1569,6 +1569,10 @@ A sending node: 3. if (and only if) `option_shutdown_anysegwit` is negotiated: * `OP_1` through `OP_16` inclusive, followed by a single push of 2 to 40 bytes (witness program versions 1 through 16) + 4. if (and only if) `option_simple_close` is negotiated: + * `OP_RETURN` followed by one of: + * `6` to `75` inclusive followed by exactly that many bytes + * `76` followed by `76` to `80` followed by exactly that many bytes A receiving node: - if it hasn't received a `funding_signed` (if it is a funder) or a `funding_created` (if it is a fundee): @@ -1767,6 +1771,7 @@ Note: the details and requirements for the transaction being signed are in [BOLT An output is *dust* if: - It is P2SH and the amount is < 540 satoshis - It is P2WSH or P2TR and the amount is < 330 satoshis +- (No OP_RETURN of any amount is dust) Both nodes: - After a `shutdown` has been received, AND no HTLCs remain in either commitment transaction: @@ -1784,7 +1789,7 @@ The sender of `closing_complete` (aka. "the closer"): - MUST NOT set `closer_no_closee`. - MUST set exactly one of `no_closer_closee` or `closer_and_closee`. - MUST set `no_closer_closee` if the local output amount is dust. - - MAY set `no_closer_closee` if it considers the closee output amount uneconomic. + - MAY set `no_closer_closee` if it considers the closee output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`. - Otherwise (not lesser amount, cannot remove own output): - MUST NOT set `no_closer_closee`. - MUST set both `closer_no_closee` and `closer_and_closee`. @@ -1795,7 +1800,7 @@ The receiver of `closing_complete` (aka. "the closee"): - Select a signature for validation: - if the local output amount is dust: - MUST use `closer_no_closee`. - - otherwise, if it considers the closee output amount uneconomic: + - otherwise, if it considers the closee output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`: - MUST use `closer_no_closee`. - otherwise, if `closer_and_closee` is present: - MUST use `closer_and_closee`. @@ -1828,6 +1833,8 @@ The close protocol is designed to avoid any failure scenarios caused by fee disa If one side has less funds than the other, it may choose to omit its own output, and in this case dust MUST be omitted, to ensure the resulting transaction can be broadcast. +The corner case where fees are so high that both outputs are dust is addressed in two ways: paying a low fee to avoid the problem, or using an OP_RETURN (which is nver "dust"). + Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. However, sending a new `shutdown` message overrides previous ones, so you can negotiated again (even changing the output address) if you want: in this case there's a race where you could receive a `closing_complete` for the previous output address, and the signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad signatures are simply ignored. From 30d36cb3222b72fdb592a77f0d40ae6fd29a4411 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 25 Sep 2023 11:06:30 +0930 Subject: [PATCH 06/12] Feedback from Bastien - Make it clear why the OP_RETURN restrictions have two forms. - Cross-reference existing dust threshold - Lots of typo fixes - Don't set closer_and_closee if we're larger/equal, and closee is dust. - Remove Rationale on delete zero-output tx hack. --- 02-peer-protocol.md | 25 ++++++++++++++----------- 03-transactions.md | 7 +------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 54629d047..f2b5c271f 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1731,6 +1731,8 @@ satoshis, which is possible if `dust_limit_satoshis` is below 546 satoshis). No funds are at risk when that happens, but the channel must be force-closed as the closing transaction will likely never reach miners. +`OP_RETURN` is only standard if followed by PUSH opcodes, and the total script is 83 bytes or less. We are slightly stricter, to only allow a single PUSH, but there are two forms in script: one which pushes up to 75 bytes, and a longer one (OP_PUSHDATA1) which is needed for 76-80 bytes. + ### Closing Negotiation: `closing_complete` and `closing_sig` Once shutdown is complete, the channel is empty of HTLCs, there are no commitments @@ -1768,10 +1770,7 @@ This process will be repeated every time a `shutdown` message is received, which Note: the details and requirements for the transaction being signed are in [BOLT 3](03-transactions.md#closing-transaction)). -An output is *dust* if: -- It is P2SH and the amount is < 540 satoshis -- It is P2WSH or P2TR and the amount is < 330 satoshis -- (No OP_RETURN of any amount is dust) +An output is *dust* if the amount is less than the [Bitcoin Core Dust Thresholds](03-transactions.md#dust-limits). Both nodes: - After a `shutdown` has been received, AND no HTLCs remain in either commitment transaction: @@ -1782,17 +1781,21 @@ The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` so that at least one output is not dust. - MUST use the last send and received `shutdown` `scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). - If it sets `signature` fields, MUST set them as valid signature using its `funding_pubkey` of: - - `closer_noclosee`: closing transaction with only the local ("closer") output. + - `closer_no_closee`: closing transaction with only the local ("closer") output. - `no_closer_closee`: closing transaction with only the remote ("closee") output. - `closer_and_closee`: closing transaction with both the closer and closee outputs. - If the local outstanding balance (in millisatoshi) is less than the remote outstanding balance: - MUST NOT set `closer_no_closee`. - MUST set exactly one of `no_closer_closee` or `closer_and_closee`. - MUST set `no_closer_closee` if the local output amount is dust. - - MAY set `no_closer_closee` if it considers the closee output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`. + - MAY set `no_closer_closee` if it considers the local output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`. - Otherwise (not lesser amount, cannot remove own output): - MUST NOT set `no_closer_closee`. - - MUST set both `closer_no_closee` and `closer_and_closee`. + - If the closee's output amount is dust: + - MUST set `closer_no_closee`. + - SHOULD NOT set `closer_and_closee`. + - Otherwise: + - MUST set both `closer_no_closee` and `closer_and_closee`. The receiver of `closing_complete` (aka. "the closee"): - If `fee_satoshis` is greater than the closer's outstanding balance: @@ -1819,10 +1822,10 @@ The receiver of `closing_sig`: - if `tlvs` does not contain exactly one signature: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - if `tlvs` does not contain one of the tlv fields sent in `closing_complete`: - - MUST ignore `closing_complete`. + - MUST ignore `closing_sig`. - if the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): - MUST ignore `closing_complete`. - - of the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): + - if the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - otherwise: - MUST sign and broadcast the corrsponding closing transaction. @@ -1833,11 +1836,11 @@ The close protocol is designed to avoid any failure scenarios caused by fee disa If one side has less funds than the other, it may choose to omit its own output, and in this case dust MUST be omitted, to ensure the resulting transaction can be broadcast. -The corner case where fees are so high that both outputs are dust is addressed in two ways: paying a low fee to avoid the problem, or using an OP_RETURN (which is nver "dust"). +The corner case where fees are so high that both outputs are dust is addressed in two ways: paying a low fee to avoid the problem, or using an OP_RETURN (which is never "dust"). Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. -However, sending a new `shutdown` message overrides previous ones, so you can negotiated again (even changing the output address) if you want: in this case there's a race where you could receive a `closing_complete` for the previous output address, and the signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad signatures are simply ignored. +However, sending a new `shutdown` message overrides previous ones, so you can negotiate again (even changing the output address) if you want: in this case there's a race where you could receive a `closing_complete` for the previous output address, and the signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad signatures are simply ignored. If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. diff --git a/03-transactions.md b/03-transactions.md index 2e312c295..e7c3cef0e 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -423,12 +423,6 @@ Each node offering a signature: - MUST subtract the fee given by `fee_satoshis` from the closer output. -### Rationale - -The case where both sides omit their outputs due to a de-minimus channel is never expected to happen, however it is -documented here for completeness, and serves to avoid an polluting the unspent outputs. Unfortunately, the transaction -has to be at least 65 bytes to propagate, so the `OP_RETURN` includes padding. - ## Fees ### Fee Calculation @@ -552,6 +546,7 @@ Bitcoin Core defines the following dust thresholds: - pay to witness pubkey hash (p2wpkh): 294 satoshis - pay to witness script hash (p2wsh): 330 satoshis - unknown segwit versions: 354 satoshis +- `OP_RETURN` outputs: these are never dust The rationale of this calculation (implemented [here](https://github.com/bitcoin/bitcoin/blob/2aff9a36c352640a263e8b5de469710f7e80eb54/src/policy/policy.cpp#L28)) is explained in the following sections. From 959a5ae199d3d706ddac461da82969b7d80ee8ac Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 5 Dec 2023 05:24:32 +1030 Subject: [PATCH 07/12] BOLT 2: specify nSequence explicitly. We don't care, as long as it's RBF-able. This will be nicer for Taproot when mutual closes are otherwise indistinguishable from normal spends. Signed-off-by: Rusty Russell --- 02-peer-protocol.md | 4 ++++ 03-transactions.md | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index f2b5c271f..f3c4f7695 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1747,6 +1747,7 @@ This process will be repeated every time a `shutdown` message is received, which 2. data: * [`channel_id`:`channel_id`] * [`u64`:`fee_satoshis`] + * [`u32`:`sequence`] * [`closing_tlvs`:`tlvs`] 1. `tlv_stream`: `closing_tlvs` @@ -1779,6 +1780,7 @@ Both nodes: The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. - MUST set `fee_satoshis` so that at least one output is not dust. + - MUST set `sequence` to a value other than 0xFFFFFFFF. - MUST use the last send and received `shutdown` `scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). - If it sets `signature` fields, MUST set them as valid signature using its `funding_pubkey` of: - `closer_no_closee`: closing transaction with only the local ("closer") output. @@ -1800,6 +1802,8 @@ The sender of `closing_complete` (aka. "the closer"): The receiver of `closing_complete` (aka. "the closee"): - If `fee_satoshis` is greater than the closer's outstanding balance: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. + - If `sequence` is equal to 0xFFFFFFFF: + - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - Select a signature for validation: - if the local output amount is dust: - MUST use `closer_no_closee`. diff --git a/03-transactions.md b/03-transactions.md index e7c3cef0e..2d2802db5 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -396,7 +396,7 @@ than twice `dust_limit_satoshis`. This variant is used for `closing_complete` and `closing_sig` messages (i.e. where `option_simple_close` is negotiated). -In this case, the node sending `closing_complete` ("the closer") pays the fees, and the sequence is set to 0xFFFFFFFD to allow RBF. The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). +In this case, the node sending `closing_complete` ("the closer") pays the fees, and the sequence specified to allow RBF. The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). The side with lesser funds can opt to omit their own output. @@ -404,7 +404,7 @@ The side with lesser funds can opt to omit their own output. * locktime: 0 * txin count: 1 * `txin[0]` outpoint: `txid` and `output_index` from `funding_created` message - * `txin[0]` sequence: 0xFFFFFFFD + * `txin[0]` sequence: `sequence` from `closing_complete` message * `txin[0]` script bytes: 0 * `txin[0]` witness: `0 ` From 6e0db70e8cb1973758e6e3d3b8c0d6ba07f19ac1 Mon Sep 17 00:00:00 2001 From: t-bast Date: Fri, 11 Oct 2024 09:37:46 +0200 Subject: [PATCH 08/12] Set output amount to 0 when using `OP_RETURN` Bitcoin Core version 25+ will not broadcast transactions containing `OP_RETURN` outputs if their amount is greater than 0, because this amount would then be unspendable. We thus require that the output amount is set to 0 when using `OP_RETURN`. --- 02-peer-protocol.md | 5 ++++- 03-transactions.md | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index f3c4f7695..8951c4bd6 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1731,7 +1731,10 @@ satoshis, which is possible if `dust_limit_satoshis` is below 546 satoshis). No funds are at risk when that happens, but the channel must be force-closed as the closing transaction will likely never reach miners. -`OP_RETURN` is only standard if followed by PUSH opcodes, and the total script is 83 bytes or less. We are slightly stricter, to only allow a single PUSH, but there are two forms in script: one which pushes up to 75 bytes, and a longer one (OP_PUSHDATA1) which is needed for 76-80 bytes. +`OP_RETURN` is only standard if followed by PUSH opcodes, and the total script +is 83 bytes or less. We are slightly stricter, to only allow a single PUSH, but +there are two forms in script: one which pushes up to 75 bytes, and a longer +one (OP_PUSHDATA1) which is needed for 76-80 bytes. ### Closing Negotiation: `closing_complete` and `closing_sig` diff --git a/03-transactions.md b/03-transactions.md index 2d2802db5..c4692b291 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -407,13 +407,16 @@ The side with lesser funds can opt to omit their own output. * `txin[0]` sequence: `sequence` from `closing_complete` message * `txin[0]` script bytes: 0 * `txin[0]` witness: `0 ` - * txout count: 1 or 2 * The closer output: - * `txout` amount: the final balance for the closer, minus `closing_complete` `fee_satoshis`, rounded down to whole satoshis. + * `txout` amount: + * 0 if the `scriptpubkey` starts with `OP_RETURN` + * otherwise the final balance for the closer, minus `closing_complete.fee_satoshis`, rounded down to whole satoshis * `txout` script: as specified in that closer's `scriptpubkey` in its `shutdown` message * The closee output: - * `txout` amount: the final balance for the closee, rounded down to whole satoshis. + * `txout` amount: + * 0 if the `scriptpubkey` starts with `OP_RETURN` + * otherwise the final balance for the closee, rounded down to whole satoshis * `txout` script: as specified in that closee's `scriptpubkey` in its `shutdown` message ### Requirements @@ -421,7 +424,7 @@ The side with lesser funds can opt to omit their own output. Each node offering a signature: - MUST round each output down to whole satoshis. - MUST subtract the fee given by `fee_satoshis` from the closer output. - + - MUST set the output amount to 0 if the `scriptpubkey` is `OP_RETURN`. ## Fees From 47afb0e092e5f476e400b05dd629ca517f96ac91 Mon Sep 17 00:00:00 2001 From: t-bast Date: Fri, 11 Oct 2024 09:45:40 +0200 Subject: [PATCH 09/12] Allow setting `nLockTime`, not `nSequence` We always set `nSequence` to `0xFFFFFFFD`, but each node can choose the `nLockTime` they want to use for the transactions for which they are paying the fees. --- 02-peer-protocol.md | 5 +---- 03-transactions.md | 9 +++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 8951c4bd6..65a5e9bf5 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1750,7 +1750,7 @@ This process will be repeated every time a `shutdown` message is received, which 2. data: * [`channel_id`:`channel_id`] * [`u64`:`fee_satoshis`] - * [`u32`:`sequence`] + * [`u32`:`locktime`] * [`closing_tlvs`:`tlvs`] 1. `tlv_stream`: `closing_tlvs` @@ -1783,7 +1783,6 @@ Both nodes: The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. - MUST set `fee_satoshis` so that at least one output is not dust. - - MUST set `sequence` to a value other than 0xFFFFFFFF. - MUST use the last send and received `shutdown` `scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). - If it sets `signature` fields, MUST set them as valid signature using its `funding_pubkey` of: - `closer_no_closee`: closing transaction with only the local ("closer") output. @@ -1805,8 +1804,6 @@ The sender of `closing_complete` (aka. "the closer"): The receiver of `closing_complete` (aka. "the closee"): - If `fee_satoshis` is greater than the closer's outstanding balance: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - - If `sequence` is equal to 0xFFFFFFFF: - - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - Select a signature for validation: - if the local output amount is dust: - MUST use `closer_no_closee`. diff --git a/03-transactions.md b/03-transactions.md index c4692b291..6dcc3bdf3 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -396,15 +396,16 @@ than twice `dust_limit_satoshis`. This variant is used for `closing_complete` and `closing_sig` messages (i.e. where `option_simple_close` is negotiated). -In this case, the node sending `closing_complete` ("the closer") pays the fees, and the sequence specified to allow RBF. The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). +In this case, the node sending `closing_complete` ("the closer") pays the fees. +The outputs are ordered as detailed in [Transaction Output Ordering](#transaction-output-ordering). The side with lesser funds can opt to omit their own output. * version: 2 -* locktime: 0 +* locktime: `locktime` from the `closing_complete` message * txin count: 1 - * `txin[0]` outpoint: `txid` and `output_index` from `funding_created` message - * `txin[0]` sequence: `sequence` from `closing_complete` message + * `txin[0]` outpoint: `txid` and `output_index` of the channel output + * `txin[0]` sequence: 0xFFFFFFFD * `txin[0]` script bytes: 0 * `txin[0]` witness: `0 ` * txout count: 1 or 2 From 8cfc61905210f7f944f637ffe1c839cd9195099a Mon Sep 17 00:00:00 2001 From: t-bast Date: Fri, 11 Oct 2024 10:12:26 +0200 Subject: [PATCH 10/12] Address pending PR comments - add more detailed protocol flow diagram - rename sigs TLVs as suggested by @morehouse - mention `upfront_shutdown_script` as suggested by @Crypt-iQ - fix typos - reformat --- 02-peer-protocol.md | 153 +++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 53 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 65a5e9bf5..6ff30dbbc 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1509,30 +1509,58 @@ Closing happens in two stages: 2. once all HTLCs are resolved, the final channel close negotiation begins. +-------+ +-------+ - | |--(1)----- shutdown ------->| | - | |<-(2)----- shutdown --------| | + | | shutdown(scriptA1) | | + | |----------------------------->| | + | | shutdown(scriptB1) | | + | |<-----------------------------| | | | | | | | | | - | A | ... | B | + | A | .... | B | | | | | - | |--(3)-- closing_signed F1--->| | - | |<-(4)-- closing_signed F2----| | - | | ... | | - | |--(?)-- closing_signed Fn--->| | - | |<-(?)-- closing_signed Fn----| | - +-------+ +-------+ - - +-------+ +-------+ - | |--(1)----- shutdown ------->| | - | |<-(2)----- shutdown --------| | + | | closing_complete | | + | |----------------------------->| | + | | closing_complete | | + | |<-----------------------------| | + | | closing_sig | | + | |<-----------------------------| | + | | closing_sig | | + | |----------------------------->| | | | | | - | | | | - | A | ... | B | + | | | | | | | | - | |--(3a)- closing_complete Fee->| | - | |<-(3b)- closing_complete Fee--| | - | |<-(4a)- closing_sig ----------| | - | |--(4b)- closing_sig --------->| | + | | shutdown(scriptA2) | | + | |----------------------------->| | + | | closing_complete | | + | |----------------------------->| | + | | closing_sig | | + | |<-----------------------------| | + | | | | + | | | | (*) This is a concurrent update + | | | | + | | shutdown(scriptA3) | | + | |-------------------> | | + | | closing_complete | | + | |-------------------> | | + | | shutdown(scriptB2) | | + | | <-------------------| | + | | closing_complete | | + | | <-------------------| | + | | shutdown(scriptA3) | | + | | ------------------->| | + | | closing_complete | | + | | ------------------->| | (*) B doesn't answer with closing_sig because A's sig doesn't use scriptB2 + | | shutdown(scriptB2) | | + | |<------------------- | | + | | closing_complete | | + | |<------------------- | | (*) A doesn't answer with closing_sig because B's sig doesn't use scriptA3 + | | closing_complete | | + | |----------------------------->| | (*) A now uses scriptB2 and scriptA3 for closing_complete + | | closing_complete | | + | |<-----------------------------| | (*) B now uses scriptB2 and scriptA3 for closing_complete + | | closing_sig | | + | |----------------------------->| | + | | closing_sig | | + | |<-----------------------------| | +-------+ +-------+ ### Closing Initiation: `shutdown` @@ -1742,7 +1770,8 @@ Once shutdown is complete, the channel is empty of HTLCs, there are no commitmen for which a revocation is owed, and all updates are included on both commitments, the final current commitment transactions will have no HTLCs. -Each peer says what fee it will pay, and the other side simply signs that transaction. The lesser-paid peer (if either is) can opt to omit their own output from the closing tx. +Each peer says what fee it will pay, and the other side simply signs that transaction. +The lesser-paid peer (if either is) can opt to omit their own output from the closing tx. This process will be repeated every time a `shutdown` message is received, which allows re-negotiation (and RBF). @@ -1755,13 +1784,13 @@ This process will be repeated every time a `shutdown` message is received, which 1. `tlv_stream`: `closing_tlvs` 2. types: - 1. type: 1 (`closer_no_closee`) + 1. type: 1 (`closer_output_only`) 2. data: * [`signature`:`sig`] - 1. type: 2 (`no_closer_closee`) + 1. type: 2 (`closee_output_only`) 2. data: * [`signature`:`sig`] - 1. type: 3 (`closer_and_closee`) + 1. type: 3 (`closer_and_closee_outputs`) 2. data: * [`signature`:`sig`] @@ -1772,7 +1801,7 @@ This process will be repeated every time a `shutdown` message is received, which #### Requirements -Note: the details and requirements for the transaction being signed are in [BOLT 3](03-transactions.md#closing-transaction)). +Note: the details and requirements for the transaction being signed are in [BOLT 3](03-transactions.md#closing-transaction). An output is *dust* if the amount is less than the [Bitcoin Core Dust Thresholds](03-transactions.md#dust-limits). @@ -1783,36 +1812,35 @@ Both nodes: The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. - MUST set `fee_satoshis` so that at least one output is not dust. - - MUST use the last send and received `shutdown` `scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). - - If it sets `signature` fields, MUST set them as valid signature using its `funding_pubkey` of: - - `closer_no_closee`: closing transaction with only the local ("closer") output. - - `no_closer_closee`: closing transaction with only the remote ("closee") output. - - `closer_and_closee`: closing transaction with both the closer and closee outputs. + - MUST use the last sent and received `shutdown.scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). + - MUST set `signature` fields as valid signature using its `funding_pubkey` of: + - `closer_output_only`: closing transaction with only the local ("closer") output. + - `closee_output_only`: closing transaction with only the remote ("closee") output. + - `closer_and_closee_outputs`: closing transaction with both the closer and closee outputs. - If the local outstanding balance (in millisatoshi) is less than the remote outstanding balance: - - MUST NOT set `closer_no_closee`. - - MUST set exactly one of `no_closer_closee` or `closer_and_closee`. - - MUST set `no_closer_closee` if the local output amount is dust. - - MAY set `no_closer_closee` if it considers the local output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`. + - MUST NOT set `closer_output_only`. + - MUST set `closee_output_only` if the local output amount is dust. + - MAY set `closee_output_only` if it considers the local output amount uneconomical AND its `scriptpubkey` is not `OP_RETURN`. - Otherwise (not lesser amount, cannot remove own output): - - MUST NOT set `no_closer_closee`. + - MUST NOT set `closee_output_only`. - If the closee's output amount is dust: - - MUST set `closer_no_closee`. - - SHOULD NOT set `closer_and_closee`. + - MUST set `closer_output_only`. + - SHOULD NOT set `closer_and_closee_outputs`. - Otherwise: - - MUST set both `closer_no_closee` and `closer_and_closee`. + - MUST set both `closer_output_only` and `closer_and_closee_outputs`. The receiver of `closing_complete` (aka. "the closee"): - If `fee_satoshis` is greater than the closer's outstanding balance: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - Select a signature for validation: - if the local output amount is dust: - - MUST use `closer_no_closee`. - - otherwise, if it considers the closee output amount uneconomic AND its `scriptpubkey` is not `OP_RETURN`: - - MUST use `closer_no_closee`. - - otherwise, if `closer_and_closee` is present: - - MUST use `closer_and_closee`. + - MUST use `closer_output_only`. + - otherwise, if it considers the local output amount uneconomical AND its `scriptpubkey` is not `OP_RETURN`: + - MUST use `closer_output_only`. + - otherwise, if `closer_and_closee_outputs` is present: + - MUST use `closer_and_closee_outputs`. - otherwise: - - MUST use `no_closer_closee`. + - MUST use `closee_output_only`. - If the selected signature field does not exist: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - If the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): @@ -1828,29 +1856,48 @@ The receiver of `closing_sig`: - if `tlvs` does not contain one of the tlv fields sent in `closing_complete`: - MUST ignore `closing_sig`. - if the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): - - MUST ignore `closing_complete`. + - MUST ignore `closing_sig`. - if the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - otherwise: - - MUST sign and broadcast the corrsponding closing transaction. + - MUST sign and broadcast the corresponding closing transaction. ### Rationale -The close protocol is designed to avoid any failure scenarios caused by fee disagreement, since each side offers to pay its own desired fee. +The close protocol is designed to avoid any failure scenarios caused by fee disagreement, +since each side offers to pay its own desired fee. -If one side has less funds than the other, it may choose to omit its own output, and in this case dust MUST be omitted, to ensure the resulting transaction can be broadcast. +If one side has less funds than the other, it may choose to omit its own output, and in this case +dust MUST be omitted, to ensure that the resulting transaction can be broadcast. -The corner case where fees are so high that both outputs are dust is addressed in two ways: paying a low fee to avoid the problem, or using an OP_RETURN (which is never "dust"). +The corner case where fees are so high that both outputs are dust is addressed in two ways: paying +a low fee to avoid the problem, or using an OP_RETURN (which is never "dust"). If one side chooses +to use an `OP_RETURN` output, its amount must be 0 to ensure that the resulting transaction can be +broadcast. -Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. +Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child +could pay the fee on the closing transactions' behalf. If rapid processing is desired and CPFP is +not an option, the closer can RBF its previous closing transactions by sending `shutdown` again. -However, sending a new `shutdown` message overrides previous ones, so you can negotiate again (even changing the output address) if you want: in this case there's a race where you could receive a `closing_complete` for the previous output address, and the signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad signatures are simply ignored. +Sending a new `shutdown` message overrides previous ones, so you can negotiate again (even changing +the output address when `upfront_shutdown_script` was not negotiated) if you want: in this case +there's a race where you could receive `closing_complete` for the previous output address, and the +signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, +as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This +assumption that we only remember the last-sent of any message is why so many cases of bad +signatures are simply ignored. -If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. +If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it +proposes is too low), it doesn't harm the closee to sign the transaction. -Similarly, if the closer proposes a high fee, it doesn't harm the closee to sign the transaction, as the closer is paying. +Similarly, if the closer proposes a high fee, it doesn't harm the closee to sign the transaction, +as the closer is paying. -There's a slight game where each side would prefer the other side pay the fee, and proposes a minimal fee. If neither side proposes a fee which will relay, the negotiation can occur again, or the final commitment transaction can be spent. In practice, the opener has an incentive to offer a reasonable closing fee, as they would pay the fee for the commitment transaction, which also costs more to spend. +There's a slight game where each side would prefer the other side pay the fee, and proposes a +minimal fee. If neither side proposes a fee which will relay, the negotiation can occur again, +or the final commitment transaction can be spent. In practice, the opener has an incentive to +offer a reasonable closing fee, as they would pay the fee for the commitment transaction, which +also costs more to spend. ## Normal Operation From a8fd1ab74255af03f4a86a38890d54ee86b1dd4d Mon Sep 17 00:00:00 2001 From: t-bast Date: Tue, 22 Oct 2024 02:59:22 +0200 Subject: [PATCH 11/12] Add strict `shutdown` exchange for taproot channels It was previously unclear whether a node could send `shutdown` and `closing_complete` immediately after that whenever RBF-ing their previous closing transaction. While this worked for non-taproot channels, it doesn't allow a clean exchange of fresh musig2 nonces for taproot channels. We now require that whenever a node wants to start a new signing round, `shutdown` must be sent *and* received before sending `closing_complete`. --- 02-peer-protocol.md | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 6ff30dbbc..6b58d5464 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1530,29 +1530,32 @@ Closing happens in two stages: | | | | | | shutdown(scriptA2) | | | |----------------------------->| | + | | shutdown(scriptB1) | | (*) Bob doesn't update his script + | |<-----------------------------| | | | closing_complete | | | |----------------------------->| | | | closing_sig | | | |<-----------------------------| | | | | | - | | | | (*) This is a concurrent update + | | | | | | | | - | | shutdown(scriptA3) | | - | |-------------------> | | - | | closing_complete | | - | |-------------------> | | | | shutdown(scriptB2) | | - | | <-------------------| | + | |<-----------------------------| | + | | shutdown(scriptA2) | | + | |----------------------------->| | | | closing_complete | | | | <-------------------| | - | | shutdown(scriptA3) | | - | | ------------------->| | - | | closing_complete | | - | | ------------------->| | (*) B doesn't answer with closing_sig because A's sig doesn't use scriptB2 - | | shutdown(scriptB2) | | - | |<------------------- | | + | | | | + | | | | (*) This is a concurrent update while Bob is sending closing_complete + | | | | + | | shutdown(scriptA3) | | + | |-------------------> | | | | closing_complete | | | |<------------------- | | (*) A doesn't answer with closing_sig because B's sig doesn't use scriptA3 + | | shutdown(scriptA3) | | + | | ------------------->| | + | | shutdown(scriptB2) | | (*) B answers A's shutdown with his own shutdown, without any changes + | |<-----------------------------| | | | closing_complete | | | |----------------------------->| | (*) A now uses scriptB2 and scriptA3 for closing_complete | | closing_complete | | @@ -1806,8 +1809,11 @@ Note: the details and requirements for the transaction being signed are in [BOLT An output is *dust* if the amount is less than the [Bitcoin Core Dust Thresholds](03-transactions.md#dust-limits). Both nodes: - - After a `shutdown` has been received, AND no HTLCs remain in either commitment transaction: + - After a `shutdown` has been sent and received, AND no HTLCs remain in either commitment transaction: - SHOULD send a `closing_complete` message. + - When receiving `shutdown` again, if it did not send `shutdown` first: + - MUST respond with `shutdown`. + - MAY send `closing_complete` afterwards. The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. @@ -1828,6 +1834,10 @@ The sender of `closing_complete` (aka. "the closer"): - SHOULD NOT set `closer_and_closee_outputs`. - Otherwise: - MUST set both `closer_output_only` and `closer_and_closee_outputs`. + - If it wants to send another `closing_complete` (e.g. with a different `fee_satoshis`): + - MUST send `shutdown` first. + - MUST receive `shutdown` from the remote node in response. + - MUST use the `scriptpubkey`s from those `shutdown` messages. The receiver of `closing_complete` (aka. "the closee"): - If `fee_satoshis` is greater than the closer's outstanding balance: @@ -1885,7 +1895,12 @@ there's a race where you could receive `closing_complete` for the previous outpu signature won't validate. In this case, ignoring the `closing_complete` is the correct behaviour, as the new `shutdown` will trigger a new `closing_complete` with the correct signature. This assumption that we only remember the last-sent of any message is why so many cases of bad -signatures are simply ignored. +signatures are simply ignored. + +When sending a new `shutdown`, we must receive a new `shutdown` from the remote node before +sending `closing_complete`. This is necessary to be compatible with future taproot channels +that use musig2 and need to exchange random nonces every time a transaction spending the channel +output is signed. If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. From 1a3e5d8e3d6c9482d5e760be2d3d01ca64bc4674 Mon Sep 17 00:00:00 2001 From: t-bast Date: Wed, 20 Nov 2024 10:20:51 +0100 Subject: [PATCH 12/12] Fix @tnull's comments Clarify strict `shutdown` exchange requirements and fix typos. --- 02-peer-protocol.md | 17 ++++++++++------- 03-transactions.md | 3 ++- 09-features.md | 45 ++++++++++++++++++++++----------------------- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 6b58d5464..6ba527e61 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1765,7 +1765,7 @@ the closing transaction will likely never reach miners. `OP_RETURN` is only standard if followed by PUSH opcodes, and the total script is 83 bytes or less. We are slightly stricter, to only allow a single PUSH, but there are two forms in script: one which pushes up to 75 bytes, and a longer -one (OP_PUSHDATA1) which is needed for 76-80 bytes. +one (`OP_PUSHDATA1`) which is needed for 76-80 bytes. ### Closing Negotiation: `closing_complete` and `closing_sig` @@ -1819,6 +1819,7 @@ The sender of `closing_complete` (aka. "the closer"): - MUST set `fee_satoshis` to a fee less than or equal to its outstanding balance, rounded down to whole satoshis. - MUST set `fee_satoshis` so that at least one output is not dust. - MUST use the last sent and received `shutdown.scriptpubkey` to generate the closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction). + - MUST set `locktime` to the desired `nLockTime` of the closing transaction. - MUST set `signature` fields as valid signature using its `funding_pubkey` of: - `closer_output_only`: closing transaction with only the local ("closer") output. - `closee_output_only`: closing transaction with only the remote ("closee") output. @@ -1858,12 +1859,12 @@ The receiver of `closing_complete` (aka. "the closee"): - If the signature field is non-compliant with LOW-S-standard rule[LOWS](https://github.com/bitcoin/bitcoin/pull/6769): - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - MUST sign and broadcast the corresponding closing transaction. - - MUST send `closing_sig` with a single valid signature in the same tlv field as the `closing_complete`. + - MUST send `closing_sig` with a single valid signature in the same TLV field as the `closing_complete`. The receiver of `closing_sig`: - if `tlvs` does not contain exactly one signature: - MUST either send a `warning` and close the connection, or send an `error` and fail the channel. - - if `tlvs` does not contain one of the tlv fields sent in `closing_complete`: + - if `tlvs` does not contain one of the TLV fields sent in `closing_complete`: - MUST ignore `closing_sig`. - if the signature field is not valid for the corresponding closing transaction specified in [BOLT #3](03-transactions.md#closing-transaction): - MUST ignore `closing_sig`. @@ -1881,9 +1882,9 @@ If one side has less funds than the other, it may choose to omit its own output, dust MUST be omitted, to ensure that the resulting transaction can be broadcast. The corner case where fees are so high that both outputs are dust is addressed in two ways: paying -a low fee to avoid the problem, or using an OP_RETURN (which is never "dust"). If one side chooses -to use an `OP_RETURN` output, its amount must be 0 to ensure that the resulting transaction can be -broadcast. +a low fee to avoid the problem, or using an `OP_RETURN` (which is never "dust"). If one side +chooses to use an `OP_RETURN` output, its amount must be 0 to ensure that the resulting transaction +can be broadcast. Note that there is usually no reason to pay a high fee for rapid processing, since an urgent child could pay the fee on the closing transactions' behalf. If rapid processing is desired and CPFP is @@ -1900,7 +1901,9 @@ signatures are simply ignored. When sending a new `shutdown`, we must receive a new `shutdown` from the remote node before sending `closing_complete`. This is necessary to be compatible with future taproot channels that use musig2 and need to exchange random nonces every time a transaction spending the channel -output is signed. +output is signed. Note that the remote `shutdown` doesn't need to be an explicit response to the +local `shutdown` that was sent: if both nodes concurrently send `shutdown`, they can exchange +`closing_complete` immediately after receiving the remote `shutdown`. If the closer proposes a transaction which will not relay (an output is dust, or the fee rate it proposes is too low), it doesn't harm the closee to sign the transaction. diff --git a/03-transactions.md b/03-transactions.md index 6dcc3bdf3..ddc687638 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -17,6 +17,7 @@ This details the exact format of on-chain transactions, which both sides need to * [Received HTLC Outputs](#received-htlc-outputs) * [Trimmed Outputs](#trimmed-outputs) * [HTLC-timeout and HTLC-success Transactions](#htlc-timeout-and-htlc-success-transactions) + * [Legacy Closing Transaction](#legacy-closing-transaction) * [Closing Transaction](#closing-transaction) * [Fees](#fees) * [Fee Calculation](#fee-calculation) @@ -349,7 +350,7 @@ The witness script for the output is: To spend this via penalty, the remote node uses a witness stack ` 1`, and to collect the output, the local node uses an input with nSequence `to_self_delay` and a witness stack ` 0`. -## Classic Closing Transaction +## Legacy Closing Transaction This variant is used for `closing_signed` messages (i.e. where `option_simple_close` is not negotiated). diff --git a/09-features.md b/09-features.md index e498f1a54..132f0c74a 100644 --- a/09-features.md +++ b/09-features.md @@ -30,29 +30,28 @@ The Context column decodes as follows: * `9`: presented in [BOLT 11](11-payment-encoding.md) invoices. * `B`: presented in the `allowed_features` field of a blinded path. -| Bits | Name | Description | Context | Dependencies | Link | -|-------|-----------------------------------|-----------------------------------------------------------|----------|---------------------------|-----------------------------------------------------------------------| -| 0/1 | `option_data_loss_protect` | ASSUMED | | | | -| 4/5 | `option_upfront_shutdown_script` | Commits to a shutdown scriptpubkey when opening channel | IN | | [BOLT #2][bolt02-open] | -| 6/7 | `gossip_queries` | Peer has useful gossip to share | | | | -| 8/9 | `var_onion_optin` | ASSUMED | | | | -| 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | IN | | [BOLT #7][bolt07-query] | -| 12/13 | `option_static_remotekey` | ASSUMED | | | | -| 14/15 | `payment_secret` | Node supports `payment_secret` field | IN9 | | [Routing Onion Specification][bolt04] | -| 16/17 | `basic_mpp` | Node can receive basic multi-part payments | IN9 | `payment_secret` | [BOLT #4][bolt04-mpp] | -| 18/19 | `option_support_large_channel` | Can create large channels | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | -| 22/23 | `option_anchors` | Anchor commitment type with zero fee HTLC transactions | IN | | [BOLT #3][bolt03-htlc-tx], [lightning-dev][ml-sighash-single-harmful] | -| 24/25 | `option_route_blinding` | Node supports blinded paths | IN9 | | [BOLT #4][bolt04-route-blinding] | -| 26/27 | `option_shutdown_anysegwit` | Future segwit versions allowed in `shutdown` | IN | | [BOLT #2][bolt02-shutdown] | -| 28/29 | `option_dual_fund` | Use v2 of channel open, enables dual funding | IN | | [BOLT #2](02-peer-protocol.md) | -| 34/35 | `option_quiesce` | Support for `stfu` message | IN | | [BOLT #2][bolt02-quiescence] | -| 38/39 | `option_onion_messages` | Can forward onion messages | IN | | [BOLT #7](04-onion-routing.md#onion-messages) | -| 44/45 | `option_channel_type` | Node supports the `channel_type` field in open/accept | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | -| 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | -| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) | -| 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | -| 60/61 | `option_simple_close` | Simplified closing negotiation | IN | `option_shutdown_anysegwit` | [BOLT #2][bolt02-simple-close] | - +| Bits | Name | Description | Context | Dependencies | Link | +|-------|-----------------------------------|-----------------------------------------------------------|----------|-----------------------------|-----------------------------------------------------------------------| +| 0/1 | `option_data_loss_protect` | ASSUMED | | | | +| 4/5 | `option_upfront_shutdown_script` | Commits to a shutdown scriptpubkey when opening channel | IN | | [BOLT #2][bolt02-open] | +| 6/7 | `gossip_queries` | Peer has useful gossip to share | | | | +| 8/9 | `var_onion_optin` | ASSUMED | | | | +| 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | IN | | [BOLT #7][bolt07-query] | +| 12/13 | `option_static_remotekey` | ASSUMED | | | | +| 14/15 | `payment_secret` | Node supports `payment_secret` field | IN9 | | [Routing Onion Specification][bolt04] | +| 16/17 | `basic_mpp` | Node can receive basic multi-part payments | IN9 | `payment_secret` | [BOLT #4][bolt04-mpp] | +| 18/19 | `option_support_large_channel` | Can create large channels | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | +| 22/23 | `option_anchors` | Anchor commitment type with zero fee HTLC transactions | IN | | [BOLT #3][bolt03-htlc-tx], [lightning-dev][ml-sighash-single-harmful] | +| 24/25 | `option_route_blinding` | Node supports blinded paths | IN9 | | [BOLT #4][bolt04-route-blinding] | +| 26/27 | `option_shutdown_anysegwit` | Future segwit versions allowed in `shutdown` | IN | | [BOLT #2][bolt02-shutdown] | +| 28/29 | `option_dual_fund` | Use v2 of channel open, enables dual funding | IN | | [BOLT #2](02-peer-protocol.md) | +| 34/35 | `option_quiesce` | Support for `stfu` message | IN | | [BOLT #2][bolt02-quiescence] | +| 38/39 | `option_onion_messages` | Can forward onion messages | IN | | [BOLT #7](04-onion-routing.md#onion-messages) | +| 44/45 | `option_channel_type` | Node supports the `channel_type` field in open/accept | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | +| 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | +| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) | +| 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | +| 60/61 | `option_simple_close` | Simplified closing negotiation | IN | `option_shutdown_anysegwit` | [BOLT #2][bolt02-simple-close] | ## Requirements