diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 0920f5051..f61dd326e 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1944,7 +1944,7 @@ the locked transaction replaces the previous funding transaction. Each node: - If any splice transaction reaches acceptable depth: - - MUST send `splice_locked`. + - MUST send `splice_locked` with the `txid` of that transaction. Once a node has sent and received `splice_locked`: - MUST consider the locked splice transaction to be the new funding @@ -1954,18 +1954,6 @@ Once a node has sent and received `splice_locked`: - MUST send `announcement_signatures` with `short_channel_id` matching the locked splice transaction. -On reconnection: - - MUST retransmit its last `splice_locked` if the `commitment_number` - is the same as before sending `splice_locked`. - -##### Rationale - -If a disconnection happens, nodes cannot know whether their peer received -their `splice_locked` message, so they retransmit it. Redundant messages -are harmless and can be safely ignored. If updates to the commitment have -been signed, this implicitly acknowledges that `splice_locked` has been -received and doesn't need to be retransmitted. - ## Channel Close Nodes can negotiate a mutual close of the connection, which unlike a @@ -2938,6 +2926,9 @@ messages are), they are independent of requirements here. 1. type: 0 (`next_funding`) 2. data: * [`sha256`:`next_funding_txid`] + 1. type: 2 (`my_current_funding_locked`) + 2. data: + * [`sha256`:`my_current_funding_locked_txid`] `next_commitment_number`: A commitment number is a 48-bit incrementing counter for each commitment transaction; counters @@ -2996,6 +2987,13 @@ The sending node: - MUST set `next_commitment_number` to the commitment number of the `commitment_signed` it sent. - otherwise: - MUST NOT set `next_funding_txid`. + - if `option_splice` was negotiated: + - MUST set `my_current_funding_locked` to the `funding_txid` of the most recent splice + transaction for which: + - it has already sent `splice_locked` or it is ready to send `splice_locked` after `channel_reestablish`. + - AND it has already received `splice_locked` from the remote node. + - if no splice transaction was ever made on the channel: + - MUST set `my_current_funding_locked` to the initial `funding_txid` of the channel. A node: - if `next_commitment_number` is 1 in both the `channel_reestablish` it @@ -3064,11 +3062,16 @@ A receiving node: this funding transaction. A receiving node: - - MUST send `splice_locked` for the most recent splice transaction that reached - acceptable depth, unless `splice_locked` was already sent for this transaction - and `next_commitment_number` is strictly greater than the `commitment_number + 1` - that was used when `splice_locked` was previously sent (which indicates that - the previous `splice_locked` was received). + - if `my_current_funding_locked` is set: + - MUST process `my_current_funding_locked_txid` as if it was receiving + `splice_locked` for this `txid`, and thus discard the previous funding + transaction and RBF attempts if it has previously sent its own + `splice_locked` for that `txid`. + - if `my_current_funding_locked_txid` does not match the most recent + `splice_locked` it has sent: + - MUST retransmit `splice_locked`. + - otherwise: + - MUST NOT retransmit `splice_locked`. A node: - MUST NOT assume that previously-transmitted messages were lost, @@ -3129,16 +3132,6 @@ operation, which is known to have begun after a `commitment_signed` has been received — hence, the test for a `next_commitment_number` greater than 1. -A previous draft insisted that the funder "MUST remember ...if it has -broadcast the funding transaction, otherwise it MUST NOT": this was in -fact an impossible requirement. A node must either firstly commit to -disk and secondly broadcast the transaction or vice versa. The new -language reflects this reality: it's surely better to remember a -channel which hasn't been broadcast than to forget one which has! -Similarly, for the fundee's `funding_signed` message: it's better to -remember a channel that never opens (and times out) than to let the -funder open it while the fundee has forgotten it. - A node, which has somehow fallen behind (e.g. has been restored from old backup), can detect that it has fallen behind. A fallen-behind node must know it cannot broadcast its current @@ -3154,6 +3147,15 @@ interactive transaction construction, or safely abort that transaction if it was not signed by one of the peers, who has thus already removed it from its state. +`my_current_funding_locked` allows peers to detect that their `splice_locked` +was lost during the disconnection and must be retransmitted. When a splice +transaction reaches acceptable depth while peers are disconnected, it also +allows locking that splice transaction immediately after `channel_reestablish` +instead of waiting for the `splice_locked` message, which could otherwise +create a race condition with channel updates. For more details about this +race condition, see [this example](./bolt02/splicing-test.md#disconnection-with-concurrent-splice_locked). +Redundant `splice_locked` messages are harmless and can be safely ignored. + # Authors [ FIXME: Insert Author List ] diff --git a/bolt02/splicing-test.md b/bolt02/splicing-test.md index 859de6b22..e8c2a1c2f 100644 --- a/bolt02/splicing-test.md +++ b/bolt02/splicing-test.md @@ -627,17 +627,17 @@ Alice initiates a splice, but disconnects before Bob receives her tx_signatures ### Disconnection with concurrent `splice_locked` In this scenario, disconnections happen while nodes are exchanging `splice_locked`. -The `splice_locked` message must be retransmitted on reconnection until new commitments have been signed. +The `splice_locked` message must be retransmitted on reconnection if it wasn't previously received. +When `my_current_funding_locked` is set, this lets nodes immediately lock the latest splice transaction. ```text Initial active commitments: - commitment_number = 10 +------------+ | FundingTx1 | +------------+ -Alice initiates a splice, but disconnects before Bob receives her splice_locked: +Alice initiates a splice, but disconnections happen when exchanging splice_locked: Alice Bob | stfu | @@ -668,77 +668,43 @@ Alice initiates a splice, but disconnects before Bob receives her splice_locked: |---------------------X | | | Active commitments: | | - | | commitment_number = 10 | | +------------+ +------------+ | | | FundingTx1 |------->| FundingTx2 | | | +------------+ +------------+ | | - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 + | channel_reestablish | next_funding_txid = null, my_current_funding_locked_txid = funding_tx1 |----------------------------->| - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 + | channel_reestablish | next_funding_txid = null, my_current_funding_locked_txid = funding_tx1 |<-----------------------------| | splice_locked | |----------------------------->| - | splice_locked | + | splice_locked | At that point, Bob has locked funding_tx2, but Alice doesn't know it because she hasn't received splice_locked yet. | X----------------------| | | - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 + | channel_reestablish | next_funding_txid = null, my_current_funding_locked_txid = funding_tx1 |----------------------------->| - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 - |<-----------------------------| - | splice_locked | - |----------------------------->| - | splice_locked | + | channel_reestablish | next_funding_txid = null, my_current_funding_locked_txid = funding_tx2 |<-----------------------------| + | | Alice doesn't need to retransmit splice_locked, since Bob's my_current_funding_locked_txid indicates that he received it. + | | Bob's my_current_funding_locked_txid lets Alice know that Bob has locked funding_tx2 while they were disconnected and will send his splice_locked. + | | She can thus immediately lock it as well even though she hasn't received yet Bob's splice_locked. + | | | | Active commitments: - | | - | | commitment_number = 10 + | | | | +------------+ | | | FundingTx2 | | | +------------+ - | update_add_htlc | - |----------------------X | - | commit_sig | - |----------------------X | | | - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 - |----------------------------->| - | channel_reestablish | next_funding_txid = null, next_commitment_number = 11, next_revocation_number = 10 - |<-----------------------------| - | splice_locked | - |----------------------------->| - | splice_locked | - |<-----------------------------| | update_add_htlc | |----------------------------->| - | commit_sig | + | commit_sig | Alice doesn't need to sent commit_sig for funding_tx1 since funding_tx2 was locked. |----------------------------->| + | splice_locked | Bob's splice_locked is sent concurrently with Alice's update_add_htlc and commit_sig: this is fine. + |<-----------------------------| | revoke_and_ack | |<-----------------------------| | commit_sig | |<-----------------------------| | revoke_and_ack | |----------------------------->| - | | Active commitments: - | | - | | commitment_number = 11 - | | +------------+ - | | | FundingTx2 | - | | +------------+ - | | - | | A new commitment was signed, implicitly acknowledging splice_locked. - | | We thus don't need to retransmit splice_locked on reconnection. - | update_add_htlc | - |----------------------X | - | commit_sig | - |----------------------X | - | | - | channel_reestablish | next_funding_txid = null, next_commitment_number = 12, next_revocation_number = 11 - |----------------------------->| - | channel_reestablish | next_funding_txid = null, next_commitment_number = 12, next_revocation_number = 11 - |<-----------------------------| - | update_add_htlc | - |----------------------------->| - | commit_sig | - |----------------------------->| ```