Terminal 0xfe settlement can leave an upstream TLC unreconciled after #1583
Scenario
Topology: A-B-C-D, payment direction A -> D. The B-C channel is force-closed.
After the TLC expires, C-D completes RemoveTlc off-chain. The B-C TLC is settled on-chain, after which B is expected to propagate RemoveTlc to A-B.
The TLC on B-C is offered by B and received by C. After C claims its final-party balance, the remaining commitment-cell capacity, including the expired TLC, belongs to B. B can therefore complete settlement using terminal unlock 0xfe.
Intermittent failure
The result depends on B/C watchtower transaction ordering.
In the failed run:
- C first sends final-party
0xfftransaction0x43f2822701f2ea18141cd7cbc29bbf4737feedd57a809067b40a6a7f2cb342f4. - B builds explicit TLC timeout transaction
0xbc365cd3b7ae9c083b40c59a232ae07a64e455406b042e2a25f2831acffec992withunlock_type=0. - The transaction is rejected:
PoolRejectedRBF: current fee 869, expected >= 2172. - B then consumes C's settlement output using terminal
0xfetransaction0xcbc47f741c565657c9d053e6bf82cc6d394db5def6f6d666d97e7b3e2969c8bc.
The terminal 0xfe transaction settles all remaining capacity, including B's expired TLC, so the TLC is settled without a preimage.
After #1583, however, the watchtower skips final-party unlocks:
if unlock.unlock_type >= 0xFE {
continue;
}No SettledWithoutPreimage resolution is recorded. The B-C channel repeatedly logs:
on-chain settlement reconciliation incomplete; keeping ONCHAIN_SETTLEMENT_CONFIRMEDB does not propagate RemoveTlc to A-B, and A's offered TLC remains locked.
In the successful run, B's explicit unlock_type=0 transaction enters the pool before C's final-party transaction. The TLC receives an explicit timeout resolution, B-C reconciliation completes, and B propagates RemoveTlc to A-B.
Before #1583, final-party 0xfe/0xff unlocks recorded the pending TLCs as on-chain settlements. #1583 changed this behavior to ignore final-party unlocks while binding settlement proofs to exact TLC identities. In this terminal-settlement path, the B-owned TLC is settled by the 0xfe sweep, but no corresponding exact TLC resolution is produced.
Failure sequence
sequenceDiagram
autonumber
participant A
participant B
participant C
participant D
participant Chain as Mempool / chain
participant WT as Watchtower
A->>B: AddTlc
B->>C: AddTlc
C->>D: AddTlc
Note over B,C: B-C is force-closed
D-->>C: TLC expires
C->>C: C-D completes RemoveTlc off-chain
C->>Chain: Submit final-party 0xff
B->>Chain: Submit explicit timeout transaction<br/>unlock_type = 0
Chain--xB: Rejected by RBF<br/>insufficient fee
B->>Chain: Submit terminal 0xfe
Note over B,Chain: Settles all remaining capacity<br/>including B's expired TLC
Chain-->>WT: Detect 0xfe settlement
WT->>WT: unlock_type >= 0xfe<br/>continue
Note right of WT: SettledWithoutPreimage<br/>is not recorded
WT-->>B: Exact TLC resolution is missing
B->>B: Reconciliation remains incomplete
B->>B: Keep ONCHAIN_SETTLEMENT_CONFIRMED
B--xA: RemoveTlc is not propagated
Note over A,B: A-B offered TLC remains lockedSource: nervosnetwork/fiber