A proposed lnd-side partial solution to #2205. Fable's summary:
Summary
The aux sweeper must account for every P2TR output of a sweep transaction: each one either carries an asset commitment or needs an exclusion proof, and building an exclusion proof requires the output's taproot internal key (and tapscript tree, if any).
The sweeper's batching deliberately mixes required-output inputs (pre-signed second-level HTLC outputs) with normal inputs. When a required output belongs to a channel the aux sweeper does not manage — a non-asset taproot channel force-closing alongside an asset channel, with deadline-matched HTLCs — the sweep transaction contains a P2TR output whose internal key and tapscript metadata the aux sweeper never learns. It cannot prove asset exclusion for that output, so it cannot produce valid proofs for any asset in the batch.
Current failure mode
The aux sweeper's only recourse is to refuse the batch by returning an error from NotifyBroadcast. That error becomes a TxFailed event, which marks the entire input set PublishFailed and reschedules it. The same batch can then re-form and re-fail indefinitely because the retry path contains no mechanism to separate the offending input. The time-sensitive pre-signed HTLC inputs in the set stall with it, creating a real fund-loss mode if a claim misses its deadline.
The existing TODO in the fee bumper ("find out which input is causing the failure and fail that one only") points at the same gap, but even granular failure handling needs the callback to identify which output is unprovable.
Key observation
The missing metadata is not actually missing from the node. Required outputs come from the node's own channels, and the resolution-construction path computes the internal key and tapscript tree when it builds each second-level output. The current input and sweep interfaces retain only part of that information and do not propagate enough of it to the aux sweeper to construct an exclusion proof.
Proposed change
Carry taproot metadata alongside each required output: the internal key plus sufficient typed tapscript preimages or leaves to prove that the tree contains no Taproot Asset commitment, or an equivalent ready-made exclusion witness. A tapscript merkle root alone is insufficient because it reconstructs the output key but does not prove what the tree contains. Surface this metadata to the AuxSweeper at broadcast time, next to the existing outpointToTxIndex mapping in the NotifyBroadcast path.
With that in hand, the aux sweeper can emit tapscript exclusion proofs for foreign outputs, and mixed batches become fully provable. No co-batching restriction is needed, and the batching efficiency the sweeper was designed for is preserved.
Alternative considered
Forbidding co-batching structurally — never clustering inputs that carry resolution blobs with foreign required-output inputs — would also resolve the livelock, but gives up batching efficiency and leaves the underlying information gap in place. Metadata conveyance is more composable and preserves batching, at the cost of larger proofs and disclosing the foreign output's tapscript information.
A proposed lnd-side partial solution to #2205. Fable's summary:
Summary
The aux sweeper must account for every P2TR output of a sweep transaction: each one either carries an asset commitment or needs an exclusion proof, and building an exclusion proof requires the output's taproot internal key (and tapscript tree, if any).
The sweeper's batching deliberately mixes required-output inputs (pre-signed second-level HTLC outputs) with normal inputs. When a required output belongs to a channel the aux sweeper does not manage — a non-asset taproot channel force-closing alongside an asset channel, with deadline-matched HTLCs — the sweep transaction contains a P2TR output whose internal key and tapscript metadata the aux sweeper never learns. It cannot prove asset exclusion for that output, so it cannot produce valid proofs for any asset in the batch.
Current failure mode
The aux sweeper's only recourse is to refuse the batch by returning an error from
NotifyBroadcast. That error becomes aTxFailedevent, which marks the entire input setPublishFailedand reschedules it. The same batch can then re-form and re-fail indefinitely because the retry path contains no mechanism to separate the offending input. The time-sensitive pre-signed HTLC inputs in the set stall with it, creating a real fund-loss mode if a claim misses its deadline.The existing TODO in the fee bumper ("find out which input is causing the failure and fail that one only") points at the same gap, but even granular failure handling needs the callback to identify which output is unprovable.
Key observation
The missing metadata is not actually missing from the node. Required outputs come from the node's own channels, and the resolution-construction path computes the internal key and tapscript tree when it builds each second-level output. The current input and sweep interfaces retain only part of that information and do not propagate enough of it to the aux sweeper to construct an exclusion proof.
Proposed change
Carry taproot metadata alongside each required output: the internal key plus sufficient typed tapscript preimages or leaves to prove that the tree contains no Taproot Asset commitment, or an equivalent ready-made exclusion witness. A tapscript merkle root alone is insufficient because it reconstructs the output key but does not prove what the tree contains. Surface this metadata to the
AuxSweeperat broadcast time, next to the existingoutpointToTxIndexmapping in theNotifyBroadcastpath.With that in hand, the aux sweeper can emit tapscript exclusion proofs for foreign outputs, and mixed batches become fully provable. No co-batching restriction is needed, and the batching efficiency the sweeper was designed for is preserved.
Alternative considered
Forbidding co-batching structurally — never clustering inputs that carry resolution blobs with foreign required-output inputs — would also resolve the livelock, but gives up batching efficiency and leaves the underlying information gap in place. Metadata conveyance is more composable and preserves batching, at the cost of larger proofs and disclosing the foreign output's tapscript information.