chancloser: update RBF close documentation for taproot support

In this commit we, update the RBF cooperative close documentation to
comprehensively cover the taproot channel closing flow. The documentation
now explains the JIT nonce pattern, asymmetric signature roles, and the
complete nonce exchange protocol for taproot channels.

Key additions include detailed explanations of how nonces flow through
the RBF process, the distinction between closer and closee roles, and
the specific wire message extensions for PartialSigWithNonce and
NextCloseeNonce fields. The documentation also covers validation
requirements and implementation notes specific to taproot channels.

This documentation provides a complete reference for understanding
and implementing the enhanced taproot RBF cooperative close protocol.
This commit is contained in:
Olaoluwa Osuntokun
2025-07-09 20:42:51 -07:00
parent faf5d30307
commit e559c839e8

View File

@@ -178,6 +178,35 @@ The `CloseErr` state provides recovery paths when protocol violations occur:
Recovery typically involves restarting the negotiation with a new closing offer.
### RBF Nonce Flow Example
Here's how nonces flow through an RBF cooperative close with taproot:
1. **Initial Shutdown**:
- Alice sends `shutdown` with her closee nonce `NA`
- Bob sends `shutdown` with his closee nonce `NB`
2. **First Close Attempt** (Alice as closer):
- Alice sends `closing_complete`:
- Uses Bob's nonce NB (from shutdown) to create her closer signature
- Includes `PartialSigWithNonce` with her next closee nonce `NA2`
- Bob sends `closing_sig`:
- Uses Alice's nonce NA (from shutdown) to create his closee signature
- Includes `NextCloseeNonce` with his next closee nonce `NB2`
3. **RBF Iteration** (Bob as closer):
- Bob sends `closing_complete`:
- Uses Alice's nonce NA2 (from previous `PartialSigWithNonce`) to create
his closer signature
- Includes `PartialSigWithNonce` with his next closee nonce `NB3`
- Alice sends `closing_sig`:
- Uses Bob's nonce NB2 (from previous `NextCloseeNonce`) to create her
closee signature
- Includes `NextCloseeNonce` with her next closee nonce `NA3`
The pattern continues with each party using the nonce they received in the
previous round.
## Example Scenarios
### Standard Cooperative Close
@@ -211,9 +240,103 @@ Recovery typically involves restarting the negotiation with a new closing offer.
5. When agreement is reached on new fees: `ClosePending``CloseFin` (via
`txn_confirmation`)
## Taproot Channel Support
### MuSig2 Nonce Handling
For taproot channels, the cooperative close process requires coordination for
MuSig2 signature creation using a JIT (Just-In-Time) nonce pattern:
#### Nonce Exchange During Shutdown
For taproot channels using the modern RBF cooperative close flow:
- The `shutdown` message includes a single nonce field:
- `shutdown_nonce` (TLV type 8): The sender's "closee nonce" used when they
send `closing_sig`
- This simplified approach works because nonces are sent JIT with signatures
#### JIT (Just-In-Time) Nonce Pattern
The protocol uses an asymmetric signature pattern for taproot channels that
optimizes nonce delivery:
**Asymmetric Roles**:
- **Closer**: The party proposing a fee (sends `closing_complete`)
- **Closee**: The party accepting the fee (sends `closing_sig`)
**ClosingComplete (from Closer)**:
- Uses `PartialSigWithNonce` (98 bytes total):
- The partial signature (32 bytes)
- The sender's next closee nonce (66 bytes)
- Bundles the nonce because the closee hasn't seen it yet
- TLV types 5, 6, 7 (distinct from non-taproot types 1, 2, 3)
**ClosingSig (from Closee)**:
- Uses `PartialSig` (32 bytes) + separate `NextCloseeNonce`:
- The partial signature in TLV types 5, 6, 7
- The next closee nonce in TLV type 22 (66 bytes)
- Separates the nonce because the closer already knows the current nonce from
shutdown or previous `PartialSigWithNonce`
This asymmetric pattern minimizes redundancy while ensuring both parties always
have the nonces they need for signing.
#### Nonce State Management
The state machine maintains a simplified `NonceState` structure with only 2 fields:
- `LocalCloseeNonce`: Our closee nonce sent in our shutdown message
- `RemoteCloseeNonce`: The peer's closee nonce from their shutdown message
The JIT pattern eliminates complex nonce rotation:
- New nonces arrive with signatures, not pre-generated
- Remote nonces are updated automatically from `PartialSigWithNonce` in
`closing_complete`
- Local nonces are generated on-demand when creating signatures
### Wire Message Extensions
The following messages have been extended with optional TLV fields for taproot:
**shutdown**:
- Type 8: `shutdown_nonce` - Sender's closee nonce for cooperative close signing
**closing_complete**:
- Types 5, 6, 7: `PartialSigWithNonce` - Partial signature with embedded next closee nonce
- Type 5: `closer_no_closee` (closer has output, closee is dust)
- Type 6: `no_closer_closee` (closer is dust, closee has output)
- Type 7: `closer_and_closee` (both have outputs)
**closing_sig**:
- Types 5, 6, 7: `PartialSig` - Just the partial signature (32 bytes)
- Same TLV type meanings as above
- Type 22: `NextCloseeNonce` - Next closee nonce for RBF iterations (66 bytes)
### Validation Requirements
For taproot channels:
- Shutdown messages MUST include the sender's closee nonce
- ClosingComplete messages MUST use PartialSigWithNonce (includes next nonce
bundled with signature)
- ClosingSig messages MUST use PartialSig with separate NextCloseeNonce field
- Terminal offers (final RBF attempts) MAY omit next nonces to signal finality
### Implementation Notes for Nonce Handling
The MuSig2 session's `InitRemoteNonce` method is called at two specific times:
1. When processing the remote's `shutdown` message (to initialize with their
closee nonce)
2. After receiving a `closing_sig` message that contains a `NextCloseeNonce`
(for RBF iterations)
The nonce from `PartialSigWithNonce` in `closing_complete` is stored but not
immediately used with `InitRemoteNonce` - it's used when we need to sign as the
closee in the next round.
## Implementation Notes
- This state machine is implemented in the `peer.go` and `channel.go` files
within the lnd codebase
- State transitions are logged at the debug level
- The `ChanCloser` interface manages the state machine execution
- Taproot support requires the `MusigSession` interface for nonce coordination