Skip to content

Commit e94d069

Browse files
committed
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.
1 parent ec491be commit e94d069

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

lnwallet/chancloser/rbf_close.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,35 @@ The `CloseErr` state provides recovery paths when protocol violations occur:
178178

179179
Recovery typically involves restarting the negotiation with a new closing offer.
180180

181+
### RBF Nonce Flow Example
182+
183+
Here's how nonces flow through an RBF cooperative close with taproot:
184+
185+
1. **Initial Shutdown**:
186+
- Alice sends `shutdown` with her closee nonce `NA`
187+
- Bob sends `shutdown` with his closee nonce `NB`
188+
189+
2. **First Close Attempt** (Alice as closer):
190+
- Alice sends `closing_complete`:
191+
- Uses Bob's nonce NB (from shutdown) to create her closer signature
192+
- Includes `PartialSigWithNonce` with her next closee nonce `NA2`
193+
- Bob sends `closing_sig`:
194+
- Uses Alice's nonce NA (from shutdown) to create his closee signature
195+
- Includes `NextCloseeNonce` with his next closee nonce `NB2`
196+
197+
3. **RBF Iteration** (Bob as closer):
198+
- Bob sends `closing_complete`:
199+
- Uses Alice's nonce NA2 (from previous `PartialSigWithNonce`) to create
200+
his closer signature
201+
- Includes `PartialSigWithNonce` with his next closee nonce `NB3`
202+
- Alice sends `closing_sig`:
203+
- Uses Bob's nonce NB2 (from previous `NextCloseeNonce`) to create her
204+
closee signature
205+
- Includes `NextCloseeNonce` with her next closee nonce `NA3`
206+
207+
The pattern continues with each party using the nonce they received in the
208+
previous round.
209+
181210
## Example Scenarios
182211

183212
### Standard Cooperative Close
@@ -211,9 +240,103 @@ Recovery typically involves restarting the negotiation with a new closing offer.
211240
5. When agreement is reached on new fees: `ClosePending``CloseFin` (via
212241
`txn_confirmation`)
213242

243+
## Taproot Channel Support
244+
245+
### MuSig2 Nonce Handling
246+
247+
For taproot channels, the cooperative close process requires coordination for
248+
MuSig2 signature creation using a JIT (Just-In-Time) nonce pattern:
249+
250+
#### Nonce Exchange During Shutdown
251+
252+
For taproot channels using the modern RBF cooperative close flow:
253+
- The `shutdown` message includes a single nonce field:
254+
- `shutdown_nonce` (TLV type 8): The sender's "closee nonce" used when they
255+
send `closing_sig`
256+
- This simplified approach works because nonces are sent JIT with signatures
257+
258+
#### JIT (Just-In-Time) Nonce Pattern
259+
260+
The protocol uses an asymmetric signature pattern for taproot channels that
261+
optimizes nonce delivery:
262+
263+
**Asymmetric Roles**:
264+
- **Closer**: The party proposing a fee (sends `closing_complete`)
265+
- **Closee**: The party accepting the fee (sends `closing_sig`)
266+
267+
**ClosingComplete (from Closer)**:
268+
- Uses `PartialSigWithNonce` (98 bytes total):
269+
- The partial signature (32 bytes)
270+
- The sender's next closee nonce (66 bytes)
271+
- Bundles the nonce because the closee hasn't seen it yet
272+
- TLV types 5, 6, 7 (distinct from non-taproot types 1, 2, 3)
273+
274+
**ClosingSig (from Closee)**:
275+
- Uses `PartialSig` (32 bytes) + separate `NextCloseeNonce`:
276+
- The partial signature in TLV types 5, 6, 7
277+
- The next closee nonce in TLV type 22 (66 bytes)
278+
- Separates the nonce because the closer already knows the current nonce from
279+
shutdown or previous `PartialSigWithNonce`
280+
281+
This asymmetric pattern minimizes redundancy while ensuring both parties always
282+
have the nonces they need for signing.
283+
284+
#### Nonce State Management
285+
286+
The state machine maintains a simplified `NonceState` structure with only 2 fields:
287+
- `LocalCloseeNonce`: Our closee nonce sent in our shutdown message
288+
- `RemoteCloseeNonce`: The peer's closee nonce from their shutdown message
289+
290+
The JIT pattern eliminates complex nonce rotation:
291+
- New nonces arrive with signatures, not pre-generated
292+
- Remote nonces are updated automatically from `PartialSigWithNonce` in
293+
`closing_complete`
294+
- Local nonces are generated on-demand when creating signatures
295+
296+
### Wire Message Extensions
297+
298+
The following messages have been extended with optional TLV fields for taproot:
299+
300+
**shutdown**:
301+
- Type 8: `shutdown_nonce` - Sender's closee nonce for cooperative close signing
302+
303+
**closing_complete**:
304+
- Types 5, 6, 7: `PartialSigWithNonce` - Partial signature with embedded next closee nonce
305+
- Type 5: `closer_no_closee` (closer has output, closee is dust)
306+
- Type 6: `no_closer_closee` (closer is dust, closee has output)
307+
- Type 7: `closer_and_closee` (both have outputs)
308+
309+
**closing_sig**:
310+
- Types 5, 6, 7: `PartialSig` - Just the partial signature (32 bytes)
311+
- Same TLV type meanings as above
312+
- Type 22: `NextCloseeNonce` - Next closee nonce for RBF iterations (66 bytes)
313+
314+
### Validation Requirements
315+
316+
For taproot channels:
317+
- Shutdown messages MUST include the sender's closee nonce
318+
- ClosingComplete messages MUST use PartialSigWithNonce (includes next nonce
319+
bundled with signature)
320+
- ClosingSig messages MUST use PartialSig with separate NextCloseeNonce field
321+
- Terminal offers (final RBF attempts) MAY omit next nonces to signal finality
322+
323+
### Implementation Notes for Nonce Handling
324+
325+
The MuSig2 session's `InitRemoteNonce` method is called at two specific times:
326+
1. When processing the remote's `shutdown` message (to initialize with their
327+
closee nonce)
328+
329+
2. After receiving a `closing_sig` message that contains a `NextCloseeNonce`
330+
(for RBF iterations)
331+
332+
The nonce from `PartialSigWithNonce` in `closing_complete` is stored but not
333+
immediately used with `InitRemoteNonce` - it's used when we need to sign as the
334+
closee in the next round.
335+
214336
## Implementation Notes
215337

216338
- This state machine is implemented in the `peer.go` and `channel.go` files
217339
within the lnd codebase
218340
- State transitions are logged at the debug level
219341
- The `ChanCloser` interface manages the state machine execution
342+
- Taproot support requires the `MusigSession` interface for nonce coordination

0 commit comments

Comments
 (0)